NVMe-oF/TCP Export
A flexBlock device can be published as an NVMe namespace through the Linux kernel’s nvmet target, so another host attaches it with the standard nvme CLI. The initiator sees an ordinary NVMe namespace with the volume’s logical block size, and can format and mount it as usual.
This example exports /dev/ublkb0, served by flexblock@nvme1n1p1.service from the systemd page.
The export unit (target host)
Section titled “The export unit (target host)”The export unit depends on the flexBlock service the same way a mount does. That guarantees the namespace is removed before the daemon is signaled, which matters because the daemon cannot see an NVMe-oF export and would otherwise stop under it.
Install as /etc/systemd/system/nvmet-analytics.service:
[Unit]Description=NVMe-oF/TCP export of the flexBlock analytics volumeRequires=flexblock@nvme1n1p1.serviceAfter=flexblock@nvme1n1p1.service network-online.targetWants=network-online.target
[Service]Type=oneshotRemainAfterExit=yesEnvironment=NVMET=/sys/kernel/config/nvmetEnvironment=NQN=nqn.2026-09.com.example:flexblock-analyticsEnvironment=SERIAL=FLEXBLOCK-ANALYTICS1Environment=NSUUID=6f1c2a4e-3b7d-4c5e-9a8f-1d2e3f4a5b6cExecStartPre=/sbin/modprobe nvmet-tcpExecStart=/bin/sh -ec '\ mkdir -p $NVMET/subsystems/$NQN/namespaces/1; \ echo $SERIAL > $NVMET/subsystems/$NQN/attr_serial; \ echo $NSUUID > $NVMET/subsystems/$NQN/namespaces/1/device_uuid; \ echo 1 > $NVMET/subsystems/$NQN/attr_allow_any_host; \ echo /dev/ublkb0 > $NVMET/subsystems/$NQN/namespaces/1/device_path; \ echo 1 > $NVMET/subsystems/$NQN/namespaces/1/enable; \ mkdir -p $NVMET/ports/1; \ echo tcp > $NVMET/ports/1/addr_trtype; \ echo ipv4 > $NVMET/ports/1/addr_adrfam; \ echo 0.0.0.0 > $NVMET/ports/1/addr_traddr; \ echo 4420 > $NVMET/ports/1/addr_trsvcid; \ ln -sfn $NVMET/subsystems/$NQN $NVMET/ports/1/subsystems/$NQN'ExecStop=/bin/sh -c '\ rm -f $NVMET/ports/1/subsystems/$NQN; \ rmdir $NVMET/ports/1; \ echo 0 > $NVMET/subsystems/$NQN/namespaces/1/enable; \ rmdir $NVMET/subsystems/$NQN/namespaces/1; \ rmdir $NVMET/subsystems/$NQN'
[Install]WantedBy=multi-user.targetsudo systemctl daemon-reloadsudo systemctl enable --now nvmet-analytics.serviceIf you prefer nvmetcli, save the same configuration with nvmetcli save and replace the two shell blocks with nvmetcli restore and nvmetcli clear, keeping the [Unit] dependencies.
Pinned serial and UUID
Section titled “Pinned serial and UUID”The serial number and namespace UUID are pinned on purpose. Left unset, the kernel generates new random ones every time the unit recreates the subsystem. An initiator that reconnects after the export restarts would then find a namespace whose identifiers changed, drop it, and fail every outstanding I/O.
With fixed identifiers, the same namespace comes back, and the initiator can address it by the stable path /dev/disk/by-id/nvme-uuid.<NSUUID> instead of an nvmeXnY name that changes with each reconnect.
Choose your own values: a UUID from uuidgen, and a serial of at most 20 characters, unique per exported volume.
Access control
Section titled “Access control”Connecting (initiator host)
Section titled “Connecting (initiator host)”sudo modprobe nvme-tcpsudo nvme discover -t tcp -a 192.0.2.10 -s 4420sudo nvme connect -t tcp -a 192.0.2.10 -s 4420 -n nqn.2026-09.com.example:flexblock-analytics --ctrl-loss-tmo -1 --reconnect-delay 5sudo nvme listls -l /dev/disk/by-id/nvme-uuid.6f1c2a4e-3b7d-4c5e-9a8f-1d2e3f4a5b6cWhy —ctrl-loss-tmo -1
Section titled “Why —ctrl-loss-tmo -1”--ctrl-loss-tmo -1 makes the initiator retry the connection indefinitely, every --reconnect-delay seconds. By default it gives up after 600 seconds and deletes the namespace, which fails every I/O on it.
Retrying forever matches how the flexBlock device itself behaves when its daemon is away: I/O waits, then completes. An export restart, a daemon crash on the target host or a network blip therefore shows up on the initiator as a stall, not as errors. Use a finite value only where an application is better served by errors than by waiting.
Reconnecting at boot
Section titled “Reconnecting at boot”-
Put the same parameters in
/etc/nvme/discovery.conf, which thenvmf-autoconnect.servicethat ships withnvme-clireads:--transport=tcp --traddr=192.0.2.10 --trsvcid=4420 --ctrl-loss-tmo=-1 --reconnect-delay=5 -
Enable the service.
Terminal window sudo systemctl enable --now nvmf-autoconnect.service -
Mount the namespace by its
/dev/disk/by-id/nvme-uuid.*path with_netdevandnofail, so that the mount is ordered after the connection.
What the initiator sees
Section titled “What the initiator sees”| Event on the target | What the initiator sees |
|---|---|
| Stopping the flexBlock service | The export is removed first, which looks like a connection loss; the initiator keeps retrying. The daemon then flushes and stops. Starting the export again reconnects it. |
| Daemon crash | The export stays in place, and the initiator’s I/O waits for the restarted daemon. |