iSCSI & NVMe over Fabrics (NVMe-oF)
iSCSI and NVMe-oF are the two primary block-level network storage protocols on Linux. iSCSI encapsulates SCSI commands over TCP/IP and is universally supported. NVMe-oF extends the NVMe protocol over network fabrics (TCP, RDMA, Fibre Channel) for lower latency and higher performance with flash storage. For file-level network sharing instead of block access, NFS and SMB/CIFS are the standard alternatives.
iSCSI architecture
| Term | Definition |
|---|---|
| Initiator | Client that sends SCSI commands to access storage (open-iscsi on Linux) |
| Target | Server that exports storage resources (LIO target framework in kernel) |
| LUN | Logical Unit Number: individual logical device on a target |
| IQN | iSCSI Qualified Name, globally unique. Format: iqn.yyyy-mm.com.example:identifier |
| Portal | IP address and TCP port combination (default port: 3260) |
| TPG | Target Portal Group: grouping of portals sharing LUN/ACL config (Tag 1 reserved for default TPG; auto-generated tags range 2-65535) |
iSCSI target setup with targetcli
# Install
sudo dnf install targetcli # RHEL/Fedora
sudo apt install targetcli-fb # Debian/Ubuntu
sudo systemctl enable --now targetBackstores
| Backstore | Use | Command |
|---|---|---|
| block | Any TYPE_DISK block device (best performance) | backstores/block create name /dev/sdb |
| fileio | Regular file as disk image | backstores/fileio create name /path/file 10G write_thru |
| ramdisk | RAM-backed (volatile, testing only) | backstores/ramdisk create name 1G |
| pscsi | Pass-through to physical SCSI device | backstores/pscsi create name /dev/sr0 |
Complete target setup
sudo targetcli
# Create block backstore
/> backstores/block create my_disk /dev/sdb
# Create iSCSI target
/> iscsi/ create iqn.2006-04.com.example:storage.target
# Navigate to TPG1
/> cd iscsi/iqn.2006-04.com.example:storage.target/tpg1
# Create LUN
/iscsi/.../tpg1> luns/ create /backstores/block/my_disk
# Create portal
/iscsi/.../tpg1> portals/ create 192.168.1.100
# Create ACL for initiator
/iscsi/.../tpg1> acls/ create iqn.2005-03.org.open-iscsi:initiator1
# Save configuration (persists to /etc/target/saveconfig.json)
/> saveconfig
/> exitDemo mode (testing only, NOT for production)
/iscsi/.../tpg1> set attribute authentication=0 demo_mode_write_protect=0 \
generate_node_acls=1 cache_dynamic_acls=1iSCSI initiator setup
# Install
sudo dnf install iscsi-initiator-utils # RHEL/Fedora
sudo apt install open-iscsi # Debian/Ubuntu
sudo systemctl enable --now iscsid
# View current initiator IQN
cat /etc/iscsi/initiatorname.iscsiDiscovery and login
# Discover targets
iscsiadm -m discovery -t st -p 192.168.1.100:3260
# Login to specific target
iscsiadm -m node -T iqn.2006-04.com.example:storage.target \
-p 192.168.1.100 -l
# Login to all discovered targets
iscsiadm -m node -L all
# Set automatic login at boot
iscsiadm -m node -T iqn.2006-04.com.example:storage.target \
-p 192.168.1.100 --op=update -n node.startup -v automaticSessions and logout
# List active sessions
iscsiadm -m session
# Detailed session info
iscsiadm -m session -P 3
# Logout
iscsiadm -m node -T iqn.2006-04.com.example:storage.target \
-p 192.168.1.100 -u
# Rescan for new LUNs
iscsiadm -m node -T iqn.2006-04.com.example:storage.target \
-p 192.168.1.100 --rescanOnce a LUN appears as a local block device, you can layer LVM on top for flexible volume management and snapshots.
CHAP authentication
Target configuration (targetcli)
/iscsi/.../acls/iqn.2005-03.org.open-iscsi:initiator1> set auth userid=initiator_user
/iscsi/.../acls/iqn.2005-03.org.open-iscsi:initiator1> set auth password=initiator_password
# Mutual CHAP (bidirectional)
/iscsi/.../acls/...> set auth mutual_userid=target_user
/iscsi/.../acls/...> set auth mutual_password=target_password
# Enable authentication on TPG
/iscsi/.../tpg1> set attribute authentication=1Initiator configuration (/etc/iscsi/iscsid.conf)
node.session.auth.authmethod = CHAP
node.session.auth.username = initiator_user
node.session.auth.password = initiator_password
# Mutual CHAP
node.session.auth.username_in = target_user
node.session.auth.password_in = target_passwordiSCSI tuning
# /etc/iscsi/iscsid.conf
# Queue depth (high-performance)
node.session.cmds_max = 2048
node.session.queue_depth = 128
# Multipath (aggressive timeout)
node.session.timeo.replacement_timeout = 0
node.conn[0].timeo.noop_out_interval = 1
node.conn[0].timeo.noop_out_timeout = 1
# TCP window (0 = kernel autotune, recommended)
node.conn[0].tcp.window_size = 0After tuning, use disk performance benchmarking tools to measure actual throughput and latency gains.
iSER (iSCSI over RDMA)
iSER extends iSCSI to use RDMA for zero-copy data transfer, reducing CPU overhead and latency. Requires InfiniBand or RoCE hardware.
# Target: create portal, then enable iSER on it
targetcli /iscsi/.../tpg1/portals> create 192.168.1.100
targetcli /iscsi/.../tpg1/portals/192.168.1.100:3260> iser_enable
# Initiator: discover and login via iSER
iscsiadm -m discovery -t st -I iser -p 192.168.1.100
iscsiadm -m node -T iqn.2006-04.com.example:storage.target -I iser -lNVMe-oF architecture
| Term | Definition |
|---|---|
| Host | System connecting to NVMe storage (initiator) |
| Subsystem | Collection of namespaces exported as a single entity (NQN-identified) |
| Namespace | Storage volume within a subsystem (analogous to LUN) |
| Controller | I/O controller providing access to namespaces |
| Discovery Controller | Special controller for discovering available subsystems (NQN: nqn.2014-08.org.nvmexpress.discovery) |
| NQN | NVMe Qualified Name. Format: nqn.yyyy-mm.com.example:identifier |
Transport types
| Transport | Requirements | Latency |
|---|---|---|
| TCP | Standard Ethernet, routable over L3 | ~200-400μs (config-dependent) |
| RDMA (IB) | InfiniBand hardware | 5-10μs |
| RDMA (RoCEv2) | RDMA-capable NICs, lossless Ethernet (DCB/PFC) | 5-10μs |
| FC | Fibre Channel infrastructure | ~15μs |
NVMe-oF target setup (nvmet)
# Install
sudo dnf install nvmetcli # RHEL/Fedora
sudo apt install nvmetcli # Debian/Ubuntu
# Load kernel modules
modprobe nvmet
modprobe nvmet-tcp # For TCP transport
modprobe nvmet-rdma # For RDMA transport
# Mount configfs (if not already)
mount -t configfs none /sys/kernel/config/Manual configuration via configfs
# Create subsystem
mkdir /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage
# Allow any host (disable for explicit access control)
echo 1 > /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/attr_allow_any_host
# Create namespace
mkdir /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/namespaces/1
# Set device path
echo -n /dev/sdb > /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/namespaces/1/device_path
# Enable namespace
echo 1 > /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/namespaces/1/enable
# Create port
mkdir /sys/kernel/config/nvmet/ports/1
# Configure transport
echo tcp > /sys/kernel/config/nvmet/ports/1/addr_trtype
echo ipv4 > /sys/kernel/config/nvmet/ports/1/addr_adrfam
echo 192.168.1.100 > /sys/kernel/config/nvmet/ports/1/addr_traddr
echo 4420 > /sys/kernel/config/nvmet/ports/1/addr_trsvcid
# Link subsystem to port
ln -s /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage \
/sys/kernel/config/nvmet/ports/1/subsystems/nqn.2016-06.com.example:storageHost access control
# Disable allow_any_host
echo 0 > /sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/attr_allow_any_host
# Create host
mkdir /sys/kernel/config/nvmet/hosts/nqn.2016-06.com.example:host1
# Link host to subsystem
ln -s /sys/kernel/config/nvmet/hosts/nqn.2016-06.com.example:host1 \
/sys/kernel/config/nvmet/subsystems/nqn.2016-06.com.example:storage/hosts/nqn.2016-06.com.example:host1NVMe-oF initiator setup
# Install
sudo dnf install nvme-cli # RHEL/Fedora
sudo apt install nvme-cli # Debian/Ubuntu
# View host NQN
nvme show-hostnqnDiscovery and connect
# Discover subsystems
nvme discover -t tcp -a 192.168.1.100 -s 4420
# Connect to specific subsystem
nvme connect -t tcp -a 192.168.1.100 -s 4420 \
-n nqn.2016-06.com.example:storage
# Connect with queue depth
nvme connect -t tcp -a 192.168.1.100 -s 4420 \
-n nqn.2016-06.com.example:storage --queue-size 1024
# Connect with controller loss timeout (seconds)
nvme connect -t tcp -a 192.168.1.100 -s 4420 \
-n nqn.2016-06.com.example:storage -l 3600
# Discover and connect to all available subsystems
nvme connect-allListing and disconnect
# List NVMe devices
nvme list
# List subsystems and paths
nvme list-subsys
# Disconnect by device
nvme disconnect -d /dev/nvme0n1
# Disconnect by NQN
nvme disconnect -n nqn.2016-06.com.example:storage
# Disconnect all
nvme disconnect-allANA (Asymmetric Namespace Access)
ANA is the NVMe-oF equivalent of SCSI ALUA, providing multipathing and path optimization. NVMe multipath is built into the kernel (not DM-Multipath).
| ANA State | Meaning |
|---|---|
| Optimized | Path is optimal for I/O |
| Non-Optimized | Path is accessible but not optimal |
| Inaccessible | Path is not accessible |
| Persistent Loss | Path is in persistent loss state |
| Transitioning | Path is transitioning between states |
# Enable NVMe multipath
modprobe nvme-multipath
# View multipath status
nvme list-subsys
# View ANA log
nvme ana-log /dev/nvme0iSCSI vs NVMe-oF comparison
| Feature | iSCSI | NVMe-oF |
|---|---|---|
| Latency | 50-100μs typical | 5-15μs (RDMA), ~200-400μs (TCP) |
| IOPS | 100K-500K typical | 500K-1M+ typical |
| CPU utilization | Higher (TCP stack) | Lower (especially RDMA) |
| Authentication | CHAP / mutual CHAP | DH-HMAC-CHAP, TLS |
| Multipathing | DM-Multipath (ALUA) | Native kernel (ANA) |
| Queue depth | Up to 2048 | 64K+ queues |
| Network requirements | Any Ethernet | TCP: any; RDMA: lossless/IB |
| Maturity | Very mature (early 2000s) | Newer, evolving ecosystem |
| Best for | General-purpose, cost-sensitive, cloud | High-performance, low-latency, flash |
Best practices
- Network isolation: use dedicated storage networks or VLANs.
- Always use authentication: CHAP for iSCSI, DH-HMAC-CHAP for NVMe-oF.
- Use mutual CHAP for bidirectional authentication.
- Configure multipathing. DM-Multipath for iSCSI, native
nvme-multipathfor NVMe-oF. - Tune queue depth based on workload and storage capabilities.
- Monitor sessions:
iscsiadm -m session,nvme list-subsys. - Use jumbo frames (9000B MTU) for better throughput on high-bandwidth links.
- For RDMA, ensure lossless Ethernet (DCB/PFC) for RoCEv2.
- Test failover by simulating path failures in a non-production environment.
Sources & references
- RFC 7143: iSCSI Protocol (Consolidated) — authoritative iSCSI specification validating protocol, IQN format, CHAP authentication, and port 3260
- NVMe over Fabrics Specification — canonical NVMe-oF specification validating architecture, transports (TCP/RDMA/FC), and ANA
- targetcli Documentation — official targetcli documentation validating LIO target setup, backstores, and configuration
- Open-iSCSI Project — primary open-iscsi repository — authoritative source for initiator implementation
Frequently asked questions
What is an iSCSI IQN?
An iSCSI Qualified Name (IQN) is a globally unique identifier for initiators and targets. The format is `iqn.yyyy-mm.com.example:identifier`, for example `iqn.2006-04.com.example:storage.target`.
What port does iSCSI use?
iSCSI uses TCP port 3260 by default. A portal is an IP address and TCP port combination.
How do I set up CHAP authentication for iSCSI?
On the target, set `auth userid` and `auth password` via targetcli, then enable `authentication=1` on the TPG. On the initiator, set `node.session.auth.authmethod = CHAP` and the credentials in `/etc/iscsi/iscsid.conf`. Use mutual CHAP for bidirectional authentication.
What is iSER?
iSER extends iSCSI to use RDMA for zero-copy data transfer, reducing CPU overhead and latency. It requires InfiniBand or RoCE hardware.
What is NVMe-oF ANA?
ANA (Asymmetric Namespace Access) is the NVMe-oF equivalent of SCSI ALUA, providing multipathing and path optimization. NVMe multipath is built into the kernel, not DM-Multipath.
How do I discover and connect to an NVMe-oF subsystem?
Run `nvme discover -t tcp -a 192.168.1.100 -s 4420` to discover subsystems, then `nvme connect -t tcp -a 192.168.1.100 -s 4420 -n nqn.2016-06.com.example:storage` to connect.
What transports does NVMe-oF support?
NVMe-oF supports TCP (~200-400μs latency, standard Ethernet), RDMA over InfiniBand or RoCEv2 (5-10μs), and Fibre Channel (~15μs).