JPOUG Advent Calendar 2021 の 7日目の投稿です。
6日目は charade_oo4o さんの Oracle on Hyper-V 2021 でした。
今日は、Oracle Linux 8 で NVMe over TCP(NVMe-TCP)ターゲットを構築してみます。
手順については、下記を参考にしています。
Oracle Linux Blog
NVMe over TCP
https://blogs.oracle.com/linux/post/nvme-over-tcp
(仮想)マシンの環境
今回は、下記のような環境を用意しました。
NVMe-TCP ターゲットを構築する VM(lab-nvmet-01)と、クライアント用の VM(lab-client-01)は、どちらも ESXi 7.0 の上で稼働しています。
どちらも、「ネットワーク アダプタ 2」を
NVMe over TCP むけネットワークに接続してあります。
そして lab-nvmet-01 には、仮想 NVMe デバイスとなる
「ハード ディスク 2」を追加してあります。
「ハード ディスク 2」は、ESXi による仮想 NVMe コントローラで接続してあります。
Oracle Linux ゲスト OS の様子
今回は、Oracle Linux 8.5 を利用します。
カーネルは、UEK R6 U3 です。(5.4.17-2136)
[root@lab-nvmet-01 ~]# cat /etc/oracle-release Oracle Linux Server release 8.5 [root@lab-nvmet-01 ~]# uname -r 5.4.17-2136.301.1.3.el8uek.x86_64
NVMe コントローラが認識されています。
ただし、これは ESXi による仮想 NVMe コントローラです。
[root@lab-stg-01 ~]# lspci | grep mem 13:00.0 Non-Volatile memory controller: VMware Device 07f0
VMware Virtual NVMe Disk__1 が、
/dev/nvme0n1 というデバイスとして認識されています。
[root@lab-stg-01 ~]# lsscsi [0:0:0:0] disk VMware Virtual disk 2.0 /dev/sda [3:0:0:0] cd/dvd NECVMWar VMware SATA CD00 1.00 /dev/sr0 [N:0:0:1] disk VMware Virtual NVMe Disk__1 /dev/nvme0n1
UEK R6 では、デフォルトで NVMe-TCP が有効にされています。
[root@lab-nvmet-01 ~]# ls /boot/config-$(uname -r) /boot/config-5.4.17-2136.301.1.3.el8uek.x86_64 [root@lab-nvmet-01 ~]# cat /boot/config-$(uname -r) | grep "NVME.*TCP" CONFIG_NVME_TCP=m CONFIG_NVME_TARGET_TCP=m
NVMe のデバイスは、nvme list でも確認できます。
[root@lab-nvmet-01 ~]# nvme list Node SN Model Namespace Usage Format FW Rev --------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- -------- /dev/nvme0n1 VMWare NVME_0000 VMware Virtual NVMe Disk 1 214.75 GB / 214.75 GB 512 B + 0 B 1.0
見栄えの都合で、JSON 形式で表示しておきます。
[root@lab-nvmet-01 ~]# nvme list -o json { "Devices" : [ { "NameSpace" : 1, "DevicePath" : "/dev/nvme0n1", "Firmware" : "1.0", "Index" : 0, "ModelNumber" : "VMware Virtual NVMe Disk", "ProductName" : "Non-Volatile memory controller: VMware Device 0x07f0", "SerialNumber" : "VMWare NVME_0000", "UsedBytes" : 214748364800, "MaximumLBA" : 419430400, "PhysicalSize" : 214748364800, "SectorSize" : 512 } ] }
NVMe-TCP ターゲットの構築
firewalld は、停止しておきます。
[root@lab-nvmet-01 ~]# systemctl stop firewalld [root@lab-nvmet-01 ~]# systemctl disable firewalld
NVMe-TCP に必要なモジュールを読み込んでおきます。
[root@lab-nvmet-01 ~]# modprobe nvme_tcp [root@lab-nvmet-01 ~]# modprobe nvmet [root@lab-nvmet-01 ~]# lsmod | grep nvme nvmet 94208 0 nvme_tcp 36864 0 nvme_fabrics 24576 1 nvme_tcp nvme 45056 0 nvme_core 98304 4 nvmet,nvme_tcp,nvme,nvme_fabrics
このモジュールは、OS 起動時に読み込まれるようにしておきます。
[root@lab-nvmet-01 ~]# echo nvme_tcp >> /etc/modules-load.d/nvme.conf [root@lab-nvmet-01 ~]# echo nvmet >> /etc/modules-load.d/nvme.conf [root@lab-nvmet-01 ~]# cat /etc/modules-load.d/nvme.conf nvme_tcp nvmet
今回利用する nvme コマンドと nvmetcli コマンドは、
デフォルトでインストールされていました。
[root@lab-nvmet-01 ~]# which nvme nvmetcli /usr/sbin/nvme /usr/sbin/nvmetcli [root@lab-nvmet-01 ~]# rpm -qf /usr/sbin/nvme nvme-cli-1.14-3.el8.x86_64 [root@lab-nvmet-01 ~]# rpm -qf /usr/sbin/nvmetcli nvmetcli-0.7-3.0.1.el8.noarch
ひたすら NVMe-TCP ターゲットの設定をします。
今回は参考にしたブログにあわせて、nvmetcli ではなく sysfs で設定します。
- NVMe サブシステムの名前は nvmet-test
- NVMe デバイスは /dev/nvme0n1
- ターゲットの IP アドレスは、10.12.7.11
- ポートは TCP 4420
[root@lab-nvmet-01 ~]# mkdir /sys/kernel/config/nvmet/subsystems/nvmet-test [root@lab-nvmet-01 ~]# echo 1 > /sys/kernel/config/nvmet/subsystems/nvmet-test/attr_allow_any_host [root@lab-nvmet-01 ~]# mkdir /sys/kernel/config/nvmet/subsystems/nvmet-test/namespaces/1 [root@lab-nvmet-01 ~]# echo -n /dev/nvme0n1 > /sys/kernel/config/nvmet/subsystems/nvmet-test/namespaces/1/device_path [root@lab-nvmet-01 ~]# echo 1 > /sys/kernel/config/nvmet/subsystems/nvmet-test/namespaces/1/enable [root@lab-nvmet-01 ~]# mkdir /sys/kernel/config/nvmet/ports/1 [root@lab-nvmet-01 ~]# echo 10.12.7.11 > /sys/kernel/config/nvmet/ports/1/addr_traddr [root@lab-nvmet-01 ~]# echo tcp > /sys/kernel/config/nvmet/ports/1/addr_trtype [root@lab-nvmet-01 ~]# echo 4420 > /sys/kernel/config/nvmet/ports/1/addr_trsvcid [root@lab-nvmet-01 ~]# echo ipv4 > /sys/kernel/config/nvmet/ports/1/addr_adrfam [root@lab-nvmet-01 ~]# ln -s /sys/kernel/config/nvmet/subsystems/nvmet-test/ /sys/kernel/config/nvmet/ports/1/subsystems/nvmet-test
設定を保存します。設定の永続化には、nvmetcli を利用します。
[root@lab-nvmet-01 ~]# ls /etc/nvmet/ [root@lab-nvmet-01 ~]# nvmetcli save [root@lab-nvmet-01 ~]# ls /etc/nvmet/ config.json
これで、ターゲットが設定できました。
[root@lab-nvmet-01 ~]# nvmetcli ls
OS 再起動後も、ターゲットの設定が読み込まれるようにしておきます。
[root@lab-nvmet-01 ~]# systemctl enable nvmet [root@lab-nvmet-01 ~]# systemctl start nvmet
クライアントからの接続
クライアントでも、Oracle Linux 8.5 を利用します。
[root@lab-client-01 ~]# cat /etc/oracle-release Oracle Linux Server release 8.5 [root@lab-client-01 ~]# uname -r 5.4.17-2136.301.1.3.el8uek.x86_64
クライアントのマシンには、まだ NVMe のデバイスは存在しません。
[root@lab-client-01 ~]# nvme list -o json { "Devices" : [ ] }
そのため、まだ nvme 関連モジュールも読み込まれていません。
[root@lab-client-01 ~]# lsmod | grep nvme [root@lab-client-01 ~]#
NVMe-TCP で必要なモジュールを読み込みます。
[root@lab-client-01 ~]# modprobe nvme [root@lab-client-01 ~]# modprobe nvme_tcp [root@lab-client-01 ~]# lsmod | grep nvme nvme_tcp 36864 0 nvme_fabrics 24576 1 nvme_tcp nvme 45056 0 nvme_core 98304 3 nvme_tcp,nvme,nvme_fabrics
NVMe-TCP ターゲットのデバイスを discover で検出します。
[root@lab-client-01 ~]# nvme discover -t tcp -a 10.12.7.11 -s 4420 Discovery Log Number of Records 1, Generation counter 5 =====Discovery Log Entry 0====== trtype: tcp adrfam: ipv4 subtype: nvme subsystem treq: not specified, sq flow control disable supported portid: 1 trsvcid: 4420 subnqn: nvmet-test traddr: 10.12.7.11 sectype: none
接続します。NVMe サブシステムの名前は、nvmet-test です。
[root@lab-client-01 ~]# nvme connect -t tcp -n nvmet-test -a 10.12.7.11 -s 4420
NVMe-TCP ターゲットのデバイスが接続され、/dev/nvme0n1 という名前で認識されました。
[root@lab-client-01 ~]# nvme list -o json { "Devices" : [ { "NameSpace" : 1, "DevicePath" : "/dev/nvme0n1", "Firmware" : "5.4.17-2", "Index" : 0, "ModelNumber" : "Linux", "SerialNumber" : "6adec1eff8a56335", "UsedBytes" : 214748364800, "MaximumLBA" : 419430400, "PhysicalSize" : 214748364800, "SectorSize" : 512 } ] }
lsblk でも確認してみます。nvme0n1 が認識されています。
[root@lab-client-01 ~]# lsblk -i NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 16G 0 disk |-sda1 8:1 0 600M 0 part /boot/efi |-sda2 8:2 0 1G 0 part /boot `-sda3 8:3 0 14.4G 0 part |-ol-root 252:0 0 12.8G 0 lvm / `-ol-swap 252:1 0 1.6G 0 lvm [SWAP] sr0 11:0 1 1024M 0 rom nvme0n1 259:1 0 200G 0 disk
/dev/nvme0n1 にパーティションを作成します。
[root@lab-client-01 ~]# echo "2048,," | sfdisk -uS /dev/nvme0n1 このディスクを使用しているユーザがいないかどうかを調べています ... OK ディスク /dev/nvme0n1: 200 GiB, 214748364800 バイト, 419430400 セクタ 単位: セクタ (1 * 512 = 512 バイト) セクタサイズ (論理 / 物理): 512 バイト / 512 バイト I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト >>> 新しい DOS ディスクラベルを作成しました。識別子は 0x5b17cb18 です。 /dev/nvme0n1p1: 新しいパーティション 1 をタイプ Linux、サイズ 200 GiB で作成しました。 /dev/nvme0n1p2: 終了。 新しい状態: ディスクラベルのタイプ: dos ディスク識別子: 0x5b17cb18 デバイス 起動 開始位置 終了位置 セクタ サイズ Id タイプ /dev/nvme0n1p1 2048 419430399 419428352 200G 83 Linux パーティション情報が変更されました。 ioctl() を呼び出してパーティション情報を再読み込みします。 ディスクを同期しています。
ファイルシステムを作成します。
[root@lab-client-01 ~]# mkfs -t xfs /dev/nvme0n1p1 meta-data=/dev/nvme0n1p1 isize=512 agcount=4, agsize=13107136 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 data = bsize=4096 blocks=52428544, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=25599, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 Discarding blocks...Done.
そしてマウントします。
[root@lab-client-01 ~]# mount /dev/nvme0n1p1 /mnt [root@lab-client-01 ~]# df -h /mnt ファイルシス サイズ 使用 残り 使用% マウント位置 /dev/nvme0n1p1 200G 1.5G 199G 1% /mnt
NVMe-TCP による領域に、書き込み & 読み取りができました。
[root@lab-client-01 ~]# echo "JPOUG Advent Calendar is 10th anniversary" > /mnt/motd.txt [root@lab-client-01 ~]# cat /mnt/motd.txt JPOUG Advent Calendar is 10th anniversary
/dev/nvme0n1p1 をアンマウントして、切断しておきます。
[root@lab-client-01 ~]# umount /mnt [root@lab-client-01 ~]# nvme disconnect -n nvmet-test NQN:nvmet-test disconnected 1 controller(s)
ついでに NVMe-TCP ターゲット自身でも接続
NVMe-TCP ターゲット自身でも、nvmet-test サブシステムに接続してみます。
それでは、nvme connect で接続します。
[root@lab-nvmet-01 ~]# nvme discover -t tcp -a 10.12.7.11 -s 4420 [root@lab-nvmet-01 ~]# nvme connect -t tcp -n nvmet-test -a 10.12.7.11 -s 4420
ローカル デバイス(nvme0n1)と、
NVMe-TCP 経由のデバイス(nvme1n1)として2重に認識されています。
lsblk の様子です。さきほど lab-client-01 で作成したパーティションは、
ターゲット側のローカル デバイス である nvme0n1 では、まだ認識されていません。
[root@lab-nvmet-01 ~]# lsblk -i /dev/nvme0n1 /dev/nvme1n1 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT nvme0n1 259:0 0 200G 0 disk nvme1n1 259:2 0 200G 0 disk `-nvme1n1p1 259:3 0 200G 0 part
nvme0n1 と nvme1n1 は、実際は同一デバイスなので、
partprobe で nvme0n1 のパーティション テーブルを読み直すと、
nvme0n1p1 が認識されます。
[root@lab-nvmet-01 ~]# partprobe /dev/nvme0n1 [root@lab-nvmet-01 ~]# lsblk -i /dev/nvme0n1 /dev/nvme1n1 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT nvme0n1 259:0 0 200G 0 disk `-nvme0n1p1 259:4 0 200G 0 part nvme1n1 259:2 0 200G 0 disk `-nvme1n1p1 259:3 0 200G 0 part
さきほど lab-client-01 で書き込んだテストファイルが読み取れます。
[root@lab-nvmet-01 ~]# mount /dev/nvme0n1p1 /mnt [root@lab-nvmet-01 ~]# cat /mnt/motd.txt JPOUG Advent Calendar is 10th anniversary [root@lab-nvmet-01 ~]# umount /mnt [root@lab-nvmet-01 ~]# mount /dev/nvme1n1p1 /mnt [root@lab-nvmet-01 ~]# cat /mnt/motd.txt JPOUG Advent Calendar is 10th anniversary [root@lab-nvmet-01 ~]# umount /mnt
ターゲット自身が NVMe-TCP でデバイスに接続したままだと、
OS 再起動などがうまくいかなかったりするので、切断しておきます。
[root@lab-nvmet-01 ~]# nvme disconnect -n nvmet-test NQN:nvmet-test disconnected 1 controller(s)
以上、Oracle Linux で NVMe-TCP ターゲットを構築してみる話でした。
明日の JPOUG Advent Calendar 2021 は HiroyukiNakaie さんです。
よろしくお願いします。