現在位置: ホーム / みらくるブログ / #1 DPDKを触ってみよう

#1 DPDKを触ってみよう

高速なネットワーク通信を実現する技術としてDPDK、および、それを利用したOpen vSwitchがあります。ミラクル・リナックスでは、これらの技術動向に注目して、調査・検証を行っています。本ブログでは、その中で得た知見などを継続的に紹介していきます。

はじめに

DPDKは、従来Linuxカーネルが行っていたNIC (Network Interface Card)の制御をユーザー空間で行うためのフレームワークです。カーネルにおける処理との最大の違いは、PMD (Pull Mode Driver)と呼ばれるポーリングベースの受信機構を持つことです。通常、Linuxカーネルでは、NICへのデータの到達を受けて、割り込みが発生し、それを契機に受信処理が実行されます。一方、PMDは、データ到達の確認や受信処理を専用のスレッドが継続的に行います。コンテキストスイッチや割り込みなどのオーバーヘッドを排除することで高速なパケット処理を行います。その他にも高速化のための工夫はありますが、実際に触って行く中ので他の特徴も紹介していきます。

とりあえず触ってみよう!

まずは1つのNICをDPDKによって制御してみましょう。DPDKで制御されるNICは、カーネルからは(ほぼ)完全に独立するので、実験を行う場合、下の図のように,通常使用しているNIC1に加えて、DPDKの実験用にNIC2を追加します。

01-host1.png

DPDKが対応するNICは、オフィシャルページに記載されています。対応カードの数は、Linuxカーネルよりだいぶ少なく、Intel社のものが大半です。ここでは、Intel X540-AT2を使用します。またOSは、Ubuntu 16.10を使用します。Ubuntuでは、比較的新しいバージョンのDPDKがaptでインストールできます。使用したホストマシンのスペックは以下のとおりです。

CPU Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz
Memory DDR3-1600 8GB x2
NIC1 (一般用) RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
NIC2 (DPDK用) Intel Corporation Ethernet Controller 10-Gigabit X540-AT2
OS Ubuntu 16.10
DPDK 16.07

インストールとセットアップ

次の2つのパッケージをインストールするだけです。

# apt-get install dpdk dpdk-igb-uio-dkms

次にNICをDPDKがユーザー空間で扱うためのモジュールが、起動時にロードされるように/etc/modulesに以下の行を記載します。

igb_uio

そして、DPDKによる高速化の要因のひとつであるHuge Pageを確保します。/etc/default/grubのGRUB_CMDLINE_LINUX_DEFAULT行に以下の水色で示したパラメータを追加します。下記では、1GiBのHuge Pageを4つ確保しています。

GRUB_CMDLINE_LINUX_DEFAULT="default_hugepagesz=1G hugepagesz=1G hugepages=4"

以下のコマンドで設定を有効にして再起動します。

# update-grub

再起動後、以下のようにHugePages_Totalが4で、Hugepagesizeが1048576kBになっていればOKです。

$ cat /proc/meminfo  | grep ^Huge
HugePages_Total:       4
HugePages_Free:        4
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB

また、カーネルモジュールigb_uioがロードされていることも確認しておきます。

$ lsmod | grep igb_uio
igb_uio                16384  0
uio                    20480  1 igb_uio
Huge Pageについて簡単に解説します。通常、Linuxはメモリを4KiB単位で管理しています。この単位をページと呼びます。例えば2GiBのメモリを使用する場合、524288個のページを取り扱う必要があります。Huge Pageは、管理単位を大きくすることで、扱うページ数を少なくし、そのオーバーヘッドを低減して、高速化する技術です。上記の例では、ページの単位を1GiBにしています。この場合、2つのページのみを扱うだけでよくなります。

NICのDPDKへのバインド

次のコマンドは、NICの一覧と管理状態を表示します。まだDPDKによって制御されいるNICはありませんので、Network devices using DPDK-compatible driverは、<none>になっています。

# dpdk-devbind --status

Network devices using DPDK-compatible driver
============================================
<none>

Network devices using kernel driver
===================================
0000:01:00.0 'Ethernet Controller 10-Gigabit X540-AT2' if=p1p1 drv=ixgbe unused=
0000:01:00.1 'Ethernet Controller 10-Gigabit X540-AT2' if=p1p2 drv=ixgbe unused=
0000:03:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller' if=p2p1 drv=r8169 unused= *Active*

Other network devices
=====================
<none>

X540のひとつ(PCIバス 0000:01:00.0)をDPDKの管理下に置くには次のようにします。

# dpdk-devbind -b igb_uio 0000:01:00.0

再度、状態を確認すると、ひとつのNICがDPDKの管理下にあることが分かります。

# dpdk-devbind --status

Network devices using DPDK-compatible driver
============================================
0000:01:00.0 'Ethernet Controller 10-Gigabit X540-AT2' drv=igb_uio unused=ixgbe

Network devices using kernel driver
===================================
0000:01:00.1 'Ethernet Controller 10-Gigabit X540-AT2' if=p1p2 drv=ixgbe unused=igb_uio
0000:03:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller' if=p2p1 drv=r8169 unused=igb_uio *Active*

Other network devices
=====================
<none>

疎通実験

NIC1とNIC2が通信できることを確認します。ここで注意すべきは、NIC2 (X540)は、もはやカーネルの管理下ではないため、ifconfigやpingなど、一般的なネットワークコマンドの対象外です。ここでは、次の図のようにtestpmdというDPDKに付属のツールを使って、NIC2からNIC1へパケットを送ります。

01-host2.png

次のように起動させると実験環境では以下のようなメッセージが表示されました。引数の-iは、インタラクティブモード、すなわち、プロンプトからコマンドを与えるモードで起動することを意味します。その前のハイフン2つありますが、DPDKの共通オプション(EAL command-line options)を与える場合、それらを、ハイフン2つ前に記載し、コマンド固有のオプションを、後ろに記載します。今回は、EALオプションを与えていません。

# testpmd -- -i
EAL: Detected 8 lcore(s)
EAL: Probing VFIO support...
PMD: bnxt_rte_pmd_init() called for (null)
EAL: PCI device 0000:01:00.0 on NUMA socket -1
EAL:   probe driver: 8086:1528 rte_ixgbe_pmd
EAL: PCI device 0000:01:00.1 on NUMA socket -1
EAL:   probe driver: 8086:1528 rte_ixgbe_pmd
Interactive-mode selected
USER1: create a new mbuf pool <mbuf_pool_socket_0>: n=203456, size=2176, socket=0
PMD: gntalloc: ioctl error

Warning! Cannot handle an odd number of ports with the current port topology. Configuration must be changed to have an even number of ports, or relaunch application with --port-topology=chained

Configuring Port 0 (socket 0)
Port 0: 00:00:5e:00:53:18
Checking link statuses...
Port 0 Link Up - speed 1000 Mbps - full-duplex
Done
testpmd>

上記では、後の確認するためのDPDKで使用するNIC (Port 0)のMACアドレスを水色で表示してあります。

簡易的なテストとして、NIC2からNIC1 (実際のマシン上のI/F名はp2p1)にパケットを送信します。そのために、デフォルトで有効になっている転送機能を無効にします。

testpmd> set fwd rxonly
Set rxonly packet forwarding mode

 また、NIC1 (p2p1)でパケットを受信確認をするために別のターミナルでtcpdumpを起動しておきます。ここでソースIPに192.168.0.1を指定するのは、testpmdの出力するパケットのデフォルトのソースアドレスがこの値であるためです。もちろん、実験するネットワーク環境にこのIPが実在する場合、不都合が生じますのでご注意ください。

 # tcpdump -e -i p2p1 src 192.168.0.1

この状態で、testpmdで以下の2つのコマンドを入力します。

testpmd> start tx_first

Warning! Cannot handle an odd number of ports with the current port topology. Configuration must be changed to have an even number of ports, or relaunch application with --port-topology=chained

rxonly packet forwarding - ports=1 - cores=1 - streams=1 - NUMA support disabled, MP over anonymous pages disabled
Logical Core 1 (socket 0) forwards packets on 1 streams:
  RX P=0/Q=0 (socket 0) -> TX P=0/Q=0 (socket 0) peer=02:00:00:00:00:00

  rxonly packet forwarding - CRC stripping disabled - packets/burst=32
  nb forwarding cores=1 - nb forwarding ports=1
  RX queues=1 - RX desc=128 - RX free threshold=32
  RX threshold registers: pthresh=8 hthresh=8 wthresh=0
  TX queues=1 - TX desc=512 - TX free threshold=32
  TX threshold registers: pthresh=32 hthresh=0 wthresh=0
  TX RS bit threshold=32 - TXQ flags=0xf01

 

testpmd> stop
Telling cores to stop...
Waiting for lcores to finish...

  ---------------------- Forward statistics for port 0  ----------------------
  RX-packets: 0              RX-dropped: 0             RX-total: 0
  TX-packets: 32             TX-dropped: 0             TX-total: 32
  ----------------------------------------------------------------------------

  +++++++++++++++ Accumulated forward statistics for all ports+++++++++++++++
  RX-packets: 0              RX-dropped: 0             RX-total: 0
  TX-packets: 32             TX-dropped: 0             TX-total: 32
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Done.

 tcpdumpの出力は以下のようになっており、送信元のMACアドレスを見ると、確かにNIC2からパケットが来ていることが分かります。

20:00:31.539982 00:00:5e:00:53:18 (oui Unknown) > 02:00:00:00:00:00 (oui Unknown), ethertype IPv4 (0x0800), length 64: 192.168.0.1.1024 > 192.168.0.2.1024: UDP, length 22
20:00:31.540001 00:00:5e:00:53:18 (oui Unknown) > 02:00:00:00:00:00 (oui Unknown), ethertype IPv4 (0x0800), length 64: 192.168.0.1.1024 > 192.168.0.2.1024: UDP, length 22
(以下省略)

今回は、疎通していることろまで確認できました。Ubuntuですと、パッケージが利用できるので環境の構築はたいへん楽でした。次回は、もう一台のマシン(OSはCentOS7.3)にDPDKを入れてパケットの対向をさせてみます。