Metonymical Deflection

ゆるく日々のコト・たまにITインフラ

CentOS7 + SPDKでNVMe-oF (NVMe over Fabric) target構築

CentOS7上でSPDKをビルドして、NVMe-oF(NVMe over Fabric) targetを構築しました。

1.環境

1-1.筐体1 NVMe over Fabric Target
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Mellanox ConnectX-3pro MCX311A-XCCT
SSD                   : Samsung SSD 250GB 970 EVO M.2 Type2280 PCIe3.0×4 NVMe1.3
Adapter                          : GLOTRENDS M.2 PCIe NVMe or PCIe AHCI SSD to PCIe 3.0 x4 Adapter Card
OS                               : CentOS7.5(1804)
Kernel                           : 4.18.4-1.el7.elrepo.x86_64
Installed Environment Groups     : Minimal Install
SPDK                         : v18.10-pre
DPDK                             : v18.05.0
1-2.筐体2 NVMe over Fabric Initiator
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Mellanox ConnectX-3pro MCX311A-XCCT
OS                               : CentOS7.5(1804)
Kernel                           : 4.18.4-1.el7.elrepo.x86_64
Installed Environment Groups     : Minimal Install
1-3.全体の構成

f:id:metonymical:20180823134430j:plain
RoCEv2のフレームをPcapしたかったためTargetとInitiatorの間にスイッチを挟んでいますが、DAS(直結)構成でも大丈夫です。

1-4.全体の流れ

Kernelのアップグレード
事前準備
SPDKのビルド
SPDKのnvmf.conf設定
NVMe-oF Initiatorからのアクセス

2.Kernelのアップグレード

今回の構成ではRoCEv2を使用します。
RoCEv2を使用する場合、Kernel4.5以上でないとサポートされないため、ELRepoから最新のKernelにアップグレードします。
この作業はTargetおよびInitiatorの両方で行ってください。

2-1.リポジトリの登録
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

GPG-KeyとELRepoの登録を実施。

# yum list installed | grep kernel
kernel.x86_64                         3.10.0-862.el7                   @anaconda
kernel-tools.x86_64                   3.10.0-862.el7                   @anaconda
kernel-tools-libs.x86_64              3.10.0-862.el7                   @anaconda

現在インストールされているKernelのバージョンを確認

2-2.Kernelのアップグレード
yum --enablerepo=elrepo-kernel install kernel-ml

最新Kernelのインストール*1

# awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
0 : CentOS Linux (4.18.4-1.el7.elrepo.x86_64) 7 (Core)
1 : CentOS Linux (3.10.0-862.el7.x86_64) 7 (Core)
2 : CentOS Linux (0-rescue-626b869879714a9cbe128e5b6f85dd89) 7 (Core)

# grub2-set-default 0
# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.18.4-1.el7.elrepo.x86_64
Found initrd image: /boot/initramfs-4.18.4-1.el7.elrepo.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-862.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-862.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-626b869879714a9cbe128e5b6f85dd89
Found initrd image: /boot/initramfs-0-rescue-626b869879714a9cbe128e5b6f85dd89.img
done
# reboot

menuentryを確認
初期起動Kernelに4.18.4-1.el7.elrepo.x86_64を選択
grub.cfgへの反映
再起動

なお、Initiatorはここまでで完了です。
Targetはspdkのビルドを行うため、この後のkernel-ml-develやkernel-ml-headersのインストールも行ってください。

2-3.既存Kernel削除とその他のアップグレード
uname -r
yum remove kernel
yum list installed | grep kernel
yum -y update kernel-tools-libs kernel-tools
yum list installed | grep kernel

起動Kernelのバージョン確認
既存Kernelの削除
現在インストールされているKernel関連のパッケージの確認
tools類のアップデート*2
現在インストールされているKernel関連のパッケージの再確認

2-4.elrepo-kernelの常時有効化
vi /etc/yum.repos.d/elrepo.repo

[elrepo-kernel]
name=ELRepo.org Community Enterprise Linux Kernel Repository - el7
baseurl=http://elrepo.org/linux/kernel/el7/$basearch/
        http://mirrors.coreix.net/elrepo/kernel/el7/$basearch/
        http://mirror.rackspace.com/elrepo/kernel/el7/$basearch/
        http://repos.lax-noc.com/elrepo/kernel/el7/$basearch/
        http://mirror.ventraip.net.au/elrepo/kernel/el7/$basearch/
mirrorlist=http://mirrors.elrepo.org/mirrors-elrepo-kernel.el7
enabled=1 #0→1に修正
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org
protect=0
2-5.tools類のアップグレードとdevel&headersのインストール
yum swap kernel-tools-libs kernel-tools -- kernel-ml-tools-libs kernel-ml-tools
yum -y install kernel-ml-devel kernel-ml-headers
yum list installed | grep kernel

kernel-*とkernel-ml-*のswap
kernel-ml-develとkernel-ml-headersのインストール
現在インストールされているKernel関連のパッケージの確認

# yum list installed | grep kernel
kernel-ml.x86_64                   4.18.4-1.el7.elrepo            @elrepo-kernel
kernel-ml-devel.x86_64             4.18.4-1.el7.elrepo            @elrepo-kernel
kernel-ml-headers.x86_64           4.18.4-1.el7.elrepo            @elrepo-kernel
kernel-ml-tools.x86_64             4.18.4-1.el7.elrepo            @elrepo-kernel
kernel-ml-tools-libs.x86_64        4.18.4-1.el7.elrepo            @elrepo-kernel

上記のような出力になっていれば完了です。

3.事前準備

3-1.セキュリティ設定の無効化

firewalldとSELinuxを無効化します。

systemctl disable firewalld

vi /etc/selinux/config
で開いて
SELINUX=disabled
にして保存。
3-2.grubの設定

grubにHugePageの設定追加

vi /etc/default/grub

GRUB_CMDLINE_LINUX=の行末に追加
default_hugepagesz=1G hugepagesz=1G hugepages=8

保存後、grubに反映
grub2-mkconfig -o /etc/grub2.cfg
3-3.NICIPアドレス設定

nmcli devなどでMellanox製NICのデバイス名を確認の上、IPアドレスを設定してください。今回構築するNVMe-oF targetはRoCEv2で動作するため、NICにはIPアドレスが必要となります。

nmcli connection add type ethernet autoconnect yes con-name ens1 ifname ens1
nmcli connection modify ens1 ipv4.method manual ipv4.addresses 192.168.20.200/24
nmcli connection up ens1
3-4.numactl-develのインストール

dpdkがnumactl-develやopenssl-devel を必要とするようなのでインストール。

yum -y install numactl-devel openssl-devel 

reboot

再起動後にHugePageを確認。
# cat /proc/meminfo | grep ^Huge
HugePages_Total:       8
HugePages_Free:        8
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB

4.SPDKのビルド

4-1.gitインストールからspdkのビルドまで

以下を流し込んでください。

yum -y install git && \
cd /usr/src && \
git clone https://github.com/spdk/spdk && \
cd spdk && \
git submodule update --init && \
scripts/pkgdep.sh && \
./configure --with-rdma --enable-debug && \
make

gitインストール
/usr/srcにcd
spdkのソースをgitから取得
/usr/src/spdkにcd*3
アップデート
必要なパッケージのインストール
makeファイル生成
ビルド

iSCSI Targetと異なる点
--with-rdmaは必須となります。
また、nvmf_tgtを起動した際に「-L」オプションでDebugログが見れるようになるため、--enable-debugを追加しています。正常起動しているのか?固まっているのか?を見極めるためにも、あった方がいいかなと思います。

4-2.unittest.shの実行

ビルドが完了したら、最後に各モジュールのテストを実施してみてください。

./test/unit/unittest.sh

 出力結果省略

=====================
All unit tests passed
=====================
WARN: lcov not installed or SPDK built without coverage!
WARN: neither valgrind nor ASAN is enabled!

多数の出力結果が表示されますが、最後に「All unit tests passed」と表示されればOKです。
Warringが2件表示されてますが、気にせず先に進んでください。

5.spdkのnvmf.confファイル設定

5-1.設定ファイルの作成
# cd /usr/src/spdk/app/nvmf_tgt
# vi nvmf.conf

[Global]
  ReactorMask 0x0F

[Nvmf]
  MaxQueuesPerSession 4
  MaxQueueDepth 1024
  AcceptorPollRate 10000

[Nvme]
  TransportId "trtype:PCIe traddr:0000:04:00.0" Nvme0
  RetryCount 4
  TimeoutUsec 1
  ActionOnTimeout None
  AdminPollRate 100000
  HotplugEnable No

[Subsystem1]
  NQN nqn.2016-06.io.spdk:cnode1
  Listen RDMA 192.168.20.200:4791
  AllowAnyHost Yes
  Host nqn.2016-06.io.spdk:init
  SN SPDK00000000000001
  Namespace Nvme0n1 1

ReactorMaskの掛け方は最後に詳細を記載したいと思います。
わからなければ、コメントアウトしても問題ありません。

TransportIdの確認方法
私の場合、Samsung SSD 250GB 970を使用したため、lspciで以下のようにgrepしました。

# lspci |grep Samsung
04:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a808

SSDのbsf(bus slot function)番号が判明したら、頭にDomain番号「0000:」を付けてください。
サンプルconfがspdk/etc/spdk/nvmf.conf.inにあるので、これをコピーしてnvmf.confを作成してもよいと思います。

5-2.setup.shの起動

カーネル上での制御からSPDK(正確にはDPDK)上での制御に移行します。
ますはステータス確認から。

# cd /usr/src/spdk
# scripts/setup.sh status
Hugepages
node     hugesize     free /  total
node0   1048576kB        8 /      8
node1   1048576kB        8 /      8
NVMe devices
BDF		Numa Node	Driver name		Device name
0000:03:00.0	0		nvme			nvme0
I/OAT DMA
BDF		Numa Node	Driver Name
0000:00:04.0	0		ioatdma
0000:20:04.0	1		ioatdma
0000:00:04.1	0		ioatdma
0000:20:04.1	1		ioatdma
0000:00:04.2	0		ioatdma
0000:20:04.2	1		ioatdma
0000:00:04.3	0		ioatdma
0000:20:04.3	1		ioatdma
0000:00:04.4	0		ioatdma
0000:20:04.4	1		ioatdma
0000:00:04.5	0		ioatdma
0000:20:04.5	1		ioatdma
0000:00:04.6	0		ioatdma
0000:20:04.6	1		ioatdma
0000:00:04.7	0		ioatdma
0000:20:04.7	1		ioatdma
virtio
BDF		Numa Node	Driver Name		Device Name

現在はカーネル上のnvmeやioatdmaドライバで制御していることがわかります。

オプション無しでsetup.shを実行すると、uio_pci_genericに移行します。*4

# scripts/setup.sh
0000:03:00.0 (144d a808): nvme -> uio_pci_generic
0000:00:04.0 (8086 3c20): ioatdma -> uio_pci_generic
0000:20:04.0 (8086 3c20): ioatdma -> uio_pci_generic
0000:00:04.1 (8086 3c21): ioatdma -> uio_pci_generic
0000:20:04.1 (8086 3c21): ioatdma -> uio_pci_generic
0000:00:04.2 (8086 3c22): ioatdma -> uio_pci_generic
0000:20:04.2 (8086 3c22): ioatdma -> uio_pci_generic
0000:00:04.3 (8086 3c23): ioatdma -> uio_pci_generic
0000:20:04.3 (8086 3c23): ioatdma -> uio_pci_generic
0000:00:04.4 (8086 3c24): ioatdma -> uio_pci_generic
0000:20:04.4 (8086 3c24): ioatdma -> uio_pci_generic
0000:00:04.5 (8086 3c25): ioatdma -> uio_pci_generic
0000:20:04.5 (8086 3c25): ioatdma -> uio_pci_generic
0000:00:04.6 (8086 3c26): ioatdma -> uio_pci_generic
0000:20:04.6 (8086 3c26): ioatdma -> uio_pci_generic
0000:00:04.7 (8086 3c27): ioatdma -> uio_pci_generic
0000:20:04.7 (8086 3c27): ioatdma -> uio_pci_generic

以下のようになっていれば、OKです。

# scripts/setup.sh status
Hugepages
node     hugesize     free /  total
node0   1048576kB        0 /      1
node1   1048576kB        0 /      1
NVMe devices
BDF             Numa Node       Driver name             Device name
0000:03:00.0    0               uio_pci_generic         -
I/OAT DMA
BDF             Numa Node       Driver Name
0000:00:04.0    0               uio_pci_generic
0000:20:04.0    1               uio_pci_generic
0000:00:04.1    0               uio_pci_generic
0000:20:04.1    1               uio_pci_generic
0000:00:04.2    0               uio_pci_generic
0000:20:04.2    1               uio_pci_generic
0000:00:04.3    0               uio_pci_generic
0000:20:04.3    1               uio_pci_generic
0000:00:04.4    0               uio_pci_generic
0000:20:04.4    1               uio_pci_generic
0000:00:04.5    0               uio_pci_generic
0000:20:04.5    1               uio_pci_generic
0000:00:04.6    0               uio_pci_generic
0000:20:04.6    1               uio_pci_generic
0000:00:04.7    0               uio_pci_generic
0000:20:04.7    1               uio_pci_generic
virtio
BDF             Numa Node       Driver Name             Device Name
5-3.Targetプログラムの実行

/usr/src/spdkのパス上で以下を実行。

app/nvmf_tgt/nvmf_tgt -c app/nvmf_tgt/nvmf.conf

以下、出力結果。
# app/nvmf_tgt/nvmf_tgt -c app/nvmf_tgt/nvmf.conf
Starting SPDK v18.07-pre / DPDK 18.02.0 initialization...
[ DPDK EAL parameters: nvmf -c 0x0F --file-prefix=spdk_pid23820 ]
EAL: Detected 8 lcore(s)
EAL: Multi-process socket /var/run/.spdk_pid23820_unix
EAL: Probing VFIO support...
app.c: 530:spdk_app_start: *NOTICE*: Total cores available: 4
reactor.c: 718:spdk_reactors_init: *NOTICE*: Occupied cpu socket mask is 0x1
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 1 on socket 0
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 2 on socket 0
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 3 on socket 0
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 0 on socket 0
EAL: PCI device 0000:03:00.0 on NUMA socket 0
EAL:   probe driver: 144d:a808 spdk_nvme
rdma.c:1454:spdk_nvmf_rdma_create: *ERROR*: rdma_create_event_channel() failed, No such device
Segmentation fault (core dumped)

初回起動時に赤文字のエラーを吐く場合は、一度サーバを再起動してみてください。

nvmf_tgtはフォアグラウンドで稼働してしまうため、上記出力(赤文字以外の出力)でプロンプトが停止したように見えますが、nvmf targetは正常に起動できています。
iscsi targetとは異なり、-b(バックグラウンド)オプションはないようです。

また、Debugオプションを使用したい場合、まずは-Lに指定可能な引数を確認するため、-hオプションでnvmf_tgtを起動してあげてください。

# app/nvmf_tgt/nvmf_tgt -h
app/nvmf_tgt/nvmf_tgt [options]
options:
 -c config  config file (default /usr/local/etc/nvmf/nvmf.conf)
 -d         disable coredump file enabling
 -e mask    tracepoint group mask for spdk trace buffers (default 0x0)
 -g         force creating just one hugetlbfs file
 -h         show this usage
 -i shared memory ID (optional)
 -m mask    core mask for DPDK
 -n channel number of memory channels used for DPDK
 -p core    master (primary) core for DPDK
 -q         disable notice level logging to stderr
 -r         RPC listen address (default /var/tmp/spdk.sock)
 -s size    memory size in MB for DPDK (default: all hugepage memory)
 -u         disable PCI access.
 -w         wait for RPCs to initialize subsystems
 -B addr    pci addr to blacklist
 -R         unlink huge files after initialization
 -W addr    pci addr to whitelist (-B and -W cannot be used at the same time)
 -L flag    enable debug log flag (all, aio, bdev, bdev_malloc, bdev_null, bdev_nvme, blob, blob_rw, copy_ioat, gpt_parse, ioat, log, lvol, lvolrpc, nbd, nvme, nvmf, rdma, reactor, rpc, vbdev_gpt, vbdev_lvol, vbdev_passthru, vbdev_split, virtio, virtio_blk, virtio_dev, virtio_pci, virtio_user)

実際にDebugオプションを付けて起動した場合は、こんな感じです。
このように起動した後、Initiatorからアクセスすると、Targetの動きがわかります。

# app/nvmf_tgt/nvmf_tgt -L nvme -L nvmf -L rdma -c app/nvmf_tgt/nvmf.conf

6.NVMe-oF Initiatorからのアクセス

6-1.Initiator側の事前準備

Initiatorのインストール

yum -y install nvme-cli

modprobe実施

modprobe ib_core
modprobe ib_umad
modprobe ib_uverbs
modprobe iw_cm
modprobe rdma_cm
modprobe rdma_ucm
modprobe mlx4_core
modprobe mlx4_ib
modprobe nvme_rdma

上記のmodprobeが正常終了していれば、以下のように/dev/nvme-fabricsが追加されているハズです。

# ls /dev/
autofs           fuse              net                 rtc       tty13  tty30  tty48  tty8     vcs6
block            hpet              network_latency     rtc0      tty14  tty31  tty49  tty9     vcsa
bsg              hpilo             network_throughput  sda       tty15  tty32  tty5   ttyS0    vcsa1
btrfs-control    hugepages         null                sda1      tty16  tty33  tty50  ttyS1    vcsa2
bus              hwrng             nvme-fabrics        sda2      tty17  tty34  tty51  ttyS2    vcsa3
centos           infiniband        nvram               sg0       tty18  tty35  tty52  ttyS3    vcsa4
char             initctl           port                sg1       tty19  tty36  tty53  uhid     vcsa5
console          input             ppp                 shm       tty2   tty37  tty54  uinput   vcsa6
core             ipmi0             ptmx                snapshot  tty20  tty38  tty55  urandom  vfio
cpu              kmsg              ptp0                snd       tty21  tty39  tty56  usbmon0  vga_arbiter
cpu_dma_latency  kvm               ptp1                stderr    tty22  tty4   tty57  usbmon1  vhci
cuse             lightnvm          ptp2                stdin     tty23  tty40  tty58  usbmon2  vhost-net
disk             log               ptp3                stdout    tty24  tty41  tty59  usbmon3  vhost-vsock
dm-0             loop-control      ptp4                tty       tty25  tty42  tty6   vcs      watchdog
dm-1             mapper            ptp5                tty0      tty26  tty43  tty60  vcs1     watchdog0
dri              mcelog            ptp6                tty1      tty27  tty44  tty61  vcs2     zero
fb0              mem               pts                 tty10     tty28  tty45  tty62  vcs3
fd               memory_bandwidth  random              tty11     tty29  tty46  tty63  vcs4
full             mqueue            raw                 tty12     tty3   tty47  tty7   vcs5

Discover実施Initiator側

# nvme discover -t rdma -a 192.168.20.200 -s 4791

Discovery Log Number of Records 1, Generation counter 4
=====Discovery Log Entry 0======
trtype:  rdma
adrfam:  ipv4
subtype: nvme subsystem
treq:    not specified
portid:  0
trsvcid: 4791
subnqn:  nqn.2016-06.io.spdk:cnode1
traddr:  192.168.20.200
rdma_prtype: not specified
rdma_qptype: connected
rdma_cms:    rdma-cm
rdma_pkey: 0x0000

Discover実施Target側

# app/nvmf_tgt/nvmf_tgt -L nvmf -c app/nvmf_tgt/nvmf.conf

request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x01 cid 1
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xbeee9c800 key 0x10110 len 0x400
ctrlr.c: 321:spdk_nvmf_ctrlr_connect: *INFO*: recfmt 0x0 qid 0 sqsize 31
ctrlr.c: 323:spdk_nvmf_ctrlr_connect: *INFO*: Connect data:
ctrlr.c: 324:spdk_nvmf_ctrlr_connect: *INFO*:   cntlid:  0xffff
ctrlr.c: 332:spdk_nvmf_ctrlr_connect: *INFO*:   hostid: 0259e14b-3479-4850-be97-f6006ffa084c ***
ctrlr.c: 349:spdk_nvmf_ctrlr_connect: *INFO*:   subnqn: "nqn.2014-08.org.nvmexpress.discovery"
ctrlr.c: 366:spdk_nvmf_ctrlr_connect: *INFO*:   hostnqn: "nqn.2014-08.org.nvmexpress:uuid:eb63ddbc-c01f-4435-8e0b-bbbaf22639f2"
ctrlr.c: 389:spdk_nvmf_ctrlr_connect: *INFO*: Connect Admin Queue for controller ID 0xffff
ctrlr.c: 207:spdk_nvmf_ctrlr_create: *INFO*: cap 0x20010103ff
ctrlr.c: 208:spdk_nvmf_ctrlr_create: *INFO*: vs 0x10300
ctrlr.c: 209:spdk_nvmf_ctrlr_create: *INFO*: cc 0x0
ctrlr.c: 210:spdk_nvmf_ctrlr_create: *INFO*: csts 0x0
ctrlr.c: 104:ctrlr_add_qpair_and_update_rsp: *INFO*: connect capsule response: cntlid = 0x0001
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=1 cdw0=0x00000001 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 1, offset 0x0
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: cap
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x20010103ff
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x010103ff rsvd1=32 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x00 cid 26
ctrlr.c: 598:spdk_nvmf_property_set: *INFO*: size 0, offset 0x14, value 0x460001
ctrlr.c: 608:spdk_nvmf_property_set: *INFO*: name: cc
ctrlr.c: 438:nvmf_prop_set_cc: *INFO*: cur CC: 0x00000000
ctrlr.c: 439:nvmf_prop_set_cc: *INFO*: new CC: 0x00460001
ctrlr.c: 449:nvmf_prop_set_cc: *INFO*: Property Set CC Enable!
ctrlr.c: 480:nvmf_prop_set_cc: *INFO*: Prop Set IOSQES = 6 (64 bytes)
ctrlr.c: 487:nvmf_prop_set_cc: *INFO*: Prop Set IOCQES = 4 (16 bytes)
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x1c
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: csts
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x1
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000001 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x8
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: vs
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x10300
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00010300 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 1, offset 0x0
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: cap
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x20010103ff
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x010103ff rsvd1=32 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x06 fuse 0 cid 26 nsid 0 cdw10 0x00000001
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xc026a1000 key 0x10111 len 0x1000
ctrlr.c:1172:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ctrlr data: maxcmd 0x400
ctrlr.c:1173:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: sgls data: 0x100005
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x02 fuse 0 cid 26 nsid 0 cdw10 0x00030070
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xc09c46000 key 0x10112 len 0x10
ctrlr.c:1082:spdk_nvmf_ctrlr_get_log_page: *INFO*: Get log page: LID=0x70 offset=0x0 len=0x10
ctrlr_discovery.c:  63:nvmf_update_discovery_log: *INFO*: Generating log page for genctr 4
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x02 fuse 0 cid 26 nsid 0 cdw10 0x01ff0070
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xbdc640000 key 0x10113 len 0x800
ctrlr.c:1082:spdk_nvmf_ctrlr_get_log_page: *INFO*: Get log page: LID=0x70 offset=0x0 len=0x800
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x00 cid 8
ctrlr.c: 598:spdk_nvmf_property_set: *INFO*: size 0, offset 0x14, value 0x464001
ctrlr.c: 608:spdk_nvmf_property_set: *INFO*: name: cc
ctrlr.c: 438:nvmf_prop_set_cc: *INFO*: cur CC: 0x00460001
ctrlr.c: 439:nvmf_prop_set_cc: *INFO*: new CC: 0x00464001
ctrlr.c: 463:nvmf_prop_set_cc: *INFO*: Property Set CC Shutdown 01b!
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=8 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 8
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x1c
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: csts
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x8
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=8 cdw0=0x00000008 rsvd1=0 status=0x0000

Connect実施Initiator側
iSCSIのときとは違い、Successなどは出力されません。

# nvme connect -t rdma -n nqn.2016-06.io.spdk:cnode1 -a 192.168.20.200 -s 4791

Connect実施Target側
Connectが完了すると、定期的にKeepaliveメッセージが流れます。

# nvme connect -t rdma -n nqn.2016-06.io.spdk:cnode1 -a 192.168.20.200 -s 4791

request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x01 cid 0
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xbeee99000 key 0x10111 len 0x400
ctrlr.c: 321:spdk_nvmf_ctrlr_connect: *INFO*: recfmt 0x0 qid 0 sqsize 31
ctrlr.c: 323:spdk_nvmf_ctrlr_connect: *INFO*: Connect data:
ctrlr.c: 324:spdk_nvmf_ctrlr_connect: *INFO*:   cntlid:  0xffff
ctrlr.c: 332:spdk_nvmf_ctrlr_connect: *INFO*:   hostid: 07ca1c45-8f62-493f-a732-7fd3c721f6f9 ***
ctrlr.c: 349:spdk_nvmf_ctrlr_connect: *INFO*:   subnqn: "nqn.2016-06.io.spdk:cnode1"
ctrlr.c: 366:spdk_nvmf_ctrlr_connect: *INFO*:   hostnqn: "nqn.2014-08.org.nvmexpress:uuid:eb63ddbc-c01f-4435-8e0b-bbbaf22639f2"
ctrlr.c: 389:spdk_nvmf_ctrlr_connect: *INFO*: Connect Admin Queue for controller ID 0xffff
ctrlr.c: 207:spdk_nvmf_ctrlr_create: *INFO*: cap 0x20010103ff
ctrlr.c: 208:spdk_nvmf_ctrlr_create: *INFO*: vs 0x10300
ctrlr.c: 209:spdk_nvmf_ctrlr_create: *INFO*: cc 0x0
ctrlr.c: 210:spdk_nvmf_ctrlr_create: *INFO*: csts 0x0
ctrlr.c: 104:ctrlr_add_qpair_and_update_rsp: *INFO*: connect capsule response: cntlid = 0x0001
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=0 cdw0=0x00000001 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 1, offset 0x0
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: cap
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x20010103ff
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x010103ff rsvd1=32 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x00 cid 26
ctrlr.c: 598:spdk_nvmf_property_set: *INFO*: size 0, offset 0x14, value 0x460001
ctrlr.c: 608:spdk_nvmf_property_set: *INFO*: name: cc
ctrlr.c: 438:nvmf_prop_set_cc: *INFO*: cur CC: 0x00000000
ctrlr.c: 439:nvmf_prop_set_cc: *INFO*: new CC: 0x00460001
ctrlr.c: 449:nvmf_prop_set_cc: *INFO*: Property Set CC Enable!
ctrlr.c: 480:nvmf_prop_set_cc: *INFO*: Prop Set IOSQES = 6 (64 bytes)
ctrlr.c: 487:nvmf_prop_set_cc: *INFO*: Prop Set IOCQES = 4 (16 bytes)
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x1c
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: csts
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x1
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000001 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x8
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: vs
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x10300
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00010300 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 26
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 1, offset 0x0
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: cap
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x20010103ff
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x010103ff rsvd1=32 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x06 fuse 0 cid 26 nsid 0 cdw10 0x00000001
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xc026a2000 key 0x10112 len 0x1000
ctrlr.c:1172:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ctrlr data: maxcmd 0x400
ctrlr.c:1173:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: sgls data: 0x100005
ctrlr_bdev.c:  73:spdk_nvmf_subsystem_bdev_io_type_supported: *INFO*: All devices in Subsystem nqn.2016-06.io.spdk:cnode1 support io_type 3
ctrlr_bdev.c:  73:spdk_nvmf_subsystem_bdev_io_type_supported: *INFO*: All devices in Subsystem nqn.2016-06.io.spdk:cnode1 support io_type 9
ctrlr.c:1215:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: ioccsz 0x104
ctrlr.c:1217:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: iorcsz 0x1
ctrlr.c:1219:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: icdoff 0x0
ctrlr.c:1221:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: ctrattr 0x0
ctrlr.c:1223:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: msdbd 0x1
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x02 fuse 0 cid 26 nsid 4294967295 cdw10 0x03ff0005
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xc026a3000 key 0x10113 len 0x1000
ctrlr.c:1082:spdk_nvmf_ctrlr_get_log_page: *INFO*: Get log page: LID=0x05 offset=0x0 len=0x1000
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=26 cdw0=0x00000000 rsvd1=0 status=0x0000

~・~一部省略~・~

ctrlr.c:1548:spdk_nvmf_ctrlr_keep_alive: *INFO*: Keep Alive
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=0 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x18 fuse 0 cid 0 nsid 0 cdw10 0x00000000
ctrlr.c:1548:spdk_nvmf_ctrlr_keep_alive: *INFO*: Keep Alive
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=0 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: o

List確認Initiator側

# nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     SPDK00000000000001   SPDK bdev Controller                     1         250.06  GB / 250.06  GB    512   B +  0 B   18.10

List確認Target側

request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x06 fuse 0 cid 18 nsid 0 cdw10 0x00000001
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xbe37f8000 key 0x10120 len 0x1000
ctrlr.c:1172:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ctrlr data: maxcmd 0x400
ctrlr.c:1173:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: sgls data: 0x100005
ctrlr_bdev.c:  73:spdk_nvmf_subsystem_bdev_io_type_supported: *INFO*: All devices in Subsystem nqn.2016-06.io.spdk:cnode1 support io_type 3
ctrlr_bdev.c:  73:spdk_nvmf_subsystem_bdev_io_type_supported: *INFO*: All devices in Subsystem nqn.2016-06.io.spdk:cnode1 support io_type 9
ctrlr.c:1215:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: ioccsz 0x104
ctrlr.c:1217:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: iorcsz 0x1
ctrlr.c:1219:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: icdoff 0x0
ctrlr.c:1221:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: ctrattr 0x0
ctrlr.c:1223:spdk_nvmf_ctrlr_identify_ctrlr: *INFO*: ext ctrlr data: msdbd 0x1
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=18 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 121:nvmf_trace_command: *INFO*: Admin cmd: opc 0x06 fuse 0 cid 18 nsid 1 cdw10 0x00000000
request.c: 136:nvmf_trace_command: *INFO*: SGL: Keyed (Inv): addr 0xbe37f8000 key 0x10121 len 0x1000
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=18 cdw0=0x00000000 rsvd1=0 status=0x0000

bdevとして認識されていることを確認*5

# lsblk
NAME            MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda               8:0    0 136.8G  0 disk
tqsda1            8:1    0     1G  0 part /boot
mqsda2            8:2    0 135.7G  0 part
  tqcentos-root 253:0    0 131.7G  0 lvm  /
  mqcentos-swap 253:1    0     4G  0 lvm  [SWAP]
sr0              11:0    1  1024M  0 rom
nvme0n1         259:0    0 232.9G  0 disk

Disconnect実施Initiator側

# nvme disconnect -n "nqn.2016-06.io.spdk:cnode1"
NQN:nqn.2016-06.io.spdk:cnode1 disconnected 1 controller(s)

Disconnect実施Target側

request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x00 cid 18
ctrlr.c: 598:spdk_nvmf_property_set: *INFO*: size 0, offset 0x14, value 0x464001
ctrlr.c: 608:spdk_nvmf_property_set: *INFO*: name: cc
ctrlr.c: 438:nvmf_prop_set_cc: *INFO*: cur CC: 0x00460001
ctrlr.c: 439:nvmf_prop_set_cc: *INFO*: new CC: 0x00464001
ctrlr.c: 463:nvmf_prop_set_cc: *INFO*: Property Set CC Shutdown 01b!
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=18 cdw0=0x00000000 rsvd1=0 status=0x0000
request.c: 116:nvmf_trace_command: *INFO*: Admin Fabrics cmd: fctype 0x04 cid 18
ctrlr.c: 557:spdk_nvmf_property_get: *INFO*: size 0, offset 0x1c
ctrlr.c: 573:spdk_nvmf_property_get: *INFO*: name: csts
ctrlr.c: 583:spdk_nvmf_property_get: *INFO*: response value: 0x8
request.c:  92:spdk_nvmf_request_complete: *INFO*: cpl: cid=18 cdw0=0x00000008 rsvd1=0 status=0x0000

上記InitiatorとTargetのやり取りをPcapしたファイルを以下にアップしておきます。
roce02.pcapng

あとは、iSCSI Targetと同様に動作しますので、Initiator側でmkfsするなり、fioで速度測定するなりご自由にどうぞ。

以上です。

7.補足その1:ReactorMaskについて

ReactorMaskとは、PMD(Poll Mode Driver)で専有させるCPUコアを明示的に指定するためのものです。NVMe-oF targetの場合、SSDが管理されているNUMA socket*6と同じNUMA socket上のCPUコアを明示的に指定することでパフォーマンスが向上します。このため、ReactorMaskでPMDが専有するCPUコアを明示的に指定することが重要となってきます。

それでは、CPUコアを明示的に指定する方法を具体例を交えて解説します。

lscpuの結果

# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 45
Model name:            Intel(R) Xeon(R) CPU E5-2407 0 @ 2.20GHz
Stepping:              7
CPU MHz:               1200.000
CPU max MHz:           2200.0000
CPU min MHz:           1200.0000
BogoMIPS:              4389.14
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              10240K
NUMA node0 CPU(s):     0-3
NUMA node1 CPU(s):     4-7
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx lahf_lm epb tpr_shadow vnmi flexpriority ept vpid xsaveopt ibpb ibrs stibp dtherm arat pln pts spec_ctrl intel_stibp

今回使用したサーバ(DL360e)の場合、2ソケット、Hyperスレッド無し、4コアなので、トータル8コアあります。
さらに、NUMA socketの割り当ては以下のようになっています。
 NUMA socket(node)0:0-3コア
 NUMA socket(node)1:4-7コア

また、nvmf_tgtの実行結果から、SSDがNUMA socket(node)0で動作していることがわかります。

# app/nvmf_tgt/nvmf_tgt -c app/nvmf_tgt/nvmf.conf
Starting SPDK v18.07-pre / DPDK 18.02.0 initialization...
[ DPDK EAL parameters: nvmf -c 0x0E --file-prefix=spdk_pid17014 ]
EAL: Detected 8 lcore(s)
EAL: Multi-process socket /var/run/.spdk_pid17014_unix
EAL: Probing VFIO support...
app.c: 530:spdk_app_start: *NOTICE*: Total cores available: 3
reactor.c: 718:spdk_reactors_init: *NOTICE*: Occupied cpu socket mask is 0x1
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 2 on socket 0
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 3 on socket 0
reactor.c: 492:_spdk_reactor_run: *NOTICE*: Reactor started on core 1 on socket 0
EAL: PCI device 0000:03:00.0 on NUMA socket 0
EAL:   probe driver: 144d:a808 spdk_nvme

上記結果より、PMDに専有させたいコアは「NUMA socket(node)0:0-3」となります。

このときのReactorMaskの指定方法は、

[Global]
  ReactorMask 0x0F

となります。

CPUコアの並び順は以下のようになっています。

7654 3210

lscpuの結果より、
 7654がNUMA socket(node)1
 3210がNUMA socket(node)0
となります。

ReactorMaskのうち、0x0Fを2進数に変換すると、以下のようになります。

16進数
0x0F
2進数
0000 1111

CPUコアの並びと2進数に変換したReactorMaskを合わせると

7654 3210
0000 1111

となり、ReactorMaskのうち「1」が立っているCPUがPMDに専有されます。
考え方としては、SubnetMaskと同様ですね。

今回の場合、あまり意味はないですが、例えば、奇数番号のコアだけを使用したい場合は、

CPUコア
7654 3210
2進数
1010 1010
16進数
0xAA

となります。

8.補足その2:fioの実施結果

fioを実施してみました。
結果、10Gbpsをフルに使用したパフォーマンスを出してくれました。
但し、Samsung SSD 250GB 970 EVOのシーケンシャルリードの公称値が3400MBps(27.2Gbps)なので、Mellanox製NICボトルネックとなっています。
これについては、40GNIC or 100GNICで試せたらいいなと考えています。

fio設定ファイル

# cat seqread4.fio

[global]
filename=/dev/nvme0n1
group_reporting=1
direct=1
ioengine=libaio

[seqread4]
readwrite=read
blocksize=32m
size=10g
numjobs=2
loops=2

fio実行結果

# fio seqread4.fio

seqread4: (g=0): rw=read, bs=(R) 32.0MiB-32.0MiB, (W) 32.0MiB-32.0MiB, (T) 32.0MiB-32.0MiB, ioengine=libaio, iodepth=1
...
fio-3.1
Starting 2 processes
Jobs: 2 (f=2): [R(2)][100.0%][r=1185MiB/s,w=0KiB/s][r=37,w=0 IOPS][eta 00m:00s]
seqread4: (groupid=0, jobs=2): err= 0: pid=13105: Thu Aug 23 15:26:47 2018
   read: IOPS=36, BW=1167MiB/s (1224MB/s)(40.0GiB/35097msec)
    slat (usec): min=26489, max=30909, avg=28159.67, stdev=289.25
    clat (usec): min=13362, max=27098, avg=26659.48, stdev=449.47
     lat (usec): min=40354, max=56431, avg=54820.49, stdev=422.94
    clat percentiles (usec):
     |  1.00th=[25560],  5.00th=[26346], 10.00th=[26346], 20.00th=[26608],
     | 30.00th=[26608], 40.00th=[26608], 50.00th=[26608], 60.00th=[26608],
     | 70.00th=[26870], 80.00th=[26870], 90.00th=[26870], 95.00th=[26870],
     | 99.00th=[26870], 99.50th=[26870], 99.90th=[27132], 99.95th=[27132],
     | 99.99th=[27132]
   bw (  KiB/s): min=588646, max=656673, per=49.95%, avg=596887.99, stdev=20330.41, samples=140
   iops        : min=   17, max=   20, avg=18.20, stdev= 0.61, samples=140
  lat (msec)   : 20=0.08%, 50=99.92%
  cpu          : usr=0.02%, sys=3.94%, ctx=21806, majf=0, minf=1107
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwt: total=1280,0,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
   READ: bw=1167MiB/s (1224MB/s), 1167MiB/s-1167MiB/s (1224MB/s-1224MB/s), io=40.0GiB (42.9GB), run=35097-35097msec

Disk stats (read/write):
  nvme0n1: ios=325850/0, merge=0/0, ticks=6298513/0, in_queue=6471868, util=99.76%

1224MBps=9792Mbps

9.最後に

以下のサイトを参考にさせて頂きました。
SPDK: NVMe over Fabrics Target
Intel SPDK NVMe-oF Target Performance Tuning. Part 2: Preparing testing environment | StarWind Blog
CentOS7でelrepoリポジトリを有効化してkernel-mlを入れる - Qiita

kernelのBugにヒットした際、仕方なく4.17系でリビルドして何とかPcapに成功したのですが、リビルドの手順も合せてこのBlogに記載するのは本編からブレるため、4.18.4がリリースされるまで待ちました。ただ予想以上に早くリリースして頂いたので、コミッターの方にはとても感謝しています。

この記事によるとNVMe市場は2020年までに570億ドル(日本円で6兆円超)規模の市場になるらしいです。
blog.calsoftinc.com

なので、早めにキャッチアップ&修得しておいて損はない技術かなと思っています。

また、以前FCoEの勉強をしていたため、RoCEは前々から気になっていました。
metonymical.hatenablog.com
FCoEはあっという間に消えてしまいましたが、RoCEはNVMe-oFのうちover Fabricの部分で残りそうな予感がしています。
oEやoCEの部分では既に規格があります*7が、RoCEv2がいいかも?と思った点は、それに加えて、IP&UDPを乗せたところだと思っています。
EthernetやIPの世界では既に400Gbpsのスイッチも市場に出始めていますし、100G×32ポート程度のスイッチであれば100万円ちょい&100GBase-SR4のQSFP28でも1万円ちょいで購入できます。
このような状況を踏まえれば、EthernetやIPをFabricとして使用したとしても、高性能なNVMe対応ストレージに対して、充分な性能を担保できるのでは?と考えています。また、導入コストやスケーラビリティの点を含めて考えても、IBやFCと対等に渡り合えるのではないかと考えています。
なので、例えば、IP CLOSネットワーク上でRoCEv2を動作させて、障害時の切替検証や複数InitiatorからTargetへのアクセス時における負荷分散など、といったシチュエーションにおける最適なネットワーク設計を検討していきたいと考えています。

*1:あえて、-yオプションを付けていません。万が一、4.18系Kernelで、4.18.4-1以前のバージョンだった場合、リポジトリからミラーサイトのURLを全て削除してください。4.18.1-1や4.18.3-1などの場合、uio_pci_genericのBugを踏むことになりTargetを起動できません。

*2:この後、yum swapしますので、最新までアップデートしてください。

*3:ここのパスが基点となります。

*4:GRUB_CMDLINE_LINUX=の行末に、intel_iommu=on iommu=pt pci=realloc も追記すると、uioの代わりにvfio-pciで稼働するようになりますが、HPのアドバイザリにヒットしたため、今回はuio_pci_genericで行っています。また、Kernel4.18系のうち、4.18.3-1以前のバージョンの場合、uio_pci_genericに移行できず、空欄となるBugを踏むことになります。

*5:setup.shの実行直後にlsblkを実行すると、nvmeはカーネルの制御から解放されているためlsblkでは見えなくなります。その後、Initiator側からConnectして、lsblkを実行すると、nvme0n1が見えるようになります。

*6:NUMA socketとかNUMA nodeと言ったりします。厳密には異なりますが、今回は同じ用語だと考えてください。

*7:DCBXとして、802.1Qau(Congestion Notification)、802.1Qaz(Enhanced Transmission Selection)、802.1Qbb(Priority-based Flow Control)に加えて、SPB、TRILLなどがあります。