nvmeof
nvmeof is a userspace NVMe over Fabrics RDMA initiator for Python. It is a
separate package layered on
ibverbs because NVMe controller and
namespace policy do not belong in low-level verbs bindings.
The data path uses NVMe/RDMA keyed SGL descriptors that point at an existing
ibverbs MR. The target transfers blocks directly to or from that MR, including
CUDA memory registered by ibverbs.cuda; there is no host staging buffer in
the NVMe-to-RDMA-to-GPU path.
Why this does not bundle SPDK
SPDK is a strong choice for a managed native storage service, but it includes
an environment abstraction, hugepage/driver setup, native plugins, and a large
dependency graph. Embedding it would not produce a self-contained, portable
pip/manylinux wheel. This package instead implements the small NVMe/RDMA host
protocol directly over the existing portable ibverbs ABI3 extension.
nvmeof itself is a pure-Python py3-none-any wheel. Its ibverbs dependency
is an ABI3 manylinux wheel that dlopens the host's libibverbs.so.1 and,
only when NVMe/RDMA is used, librdmacm.so.1.
Requirements
- Linux, an RDMA NIC, and a reachable NVMe/RDMA target.
libibverbs.so.1,librdmacm.so.1, and the matching RDMA provider.- For GPU I/O: CUDA, an HCA with GPUDirect RDMA, and dma-buf support or the
nvidia_peermemmodule. - The target must support keyed SGL data block descriptors. Separate namespace metadata and DH-HMAC-CHAP are not currently supported.
On Debian/Ubuntu the runtime packages are typically:
sudo apt-get install libibverbs1 librdmacm1 ibverbs-providers
pip install nvmeof
Controller options
Controller.connect(host, subsystem_nqn, **options) and the direct
Controller(...) constructor accept the same options:
| Option | Default | Meaning |
|---|---|---|
port |
4420 |
Target NVMe/RDMA service port. |
host_id |
random UUID | Initiator host identifier. Supply a stable UUID when target policy depends on host identity. |
host_nqn |
derived from host_id |
Initiator NQN sent in Fabrics Connect. |
queue_depth |
128 |
Requested I/O depth from 2 through 256; the controller may negotiate it downward. |
keep_alive_ms |
0 |
Keep-alive timeout. Non-zero values are currently unsupported because there is no background command worker. |
timeout |
30.0 |
Per-command timeout in seconds. |
source |
None |
Local initiator IP used to bind RDMA-CM and select the HCA. |
Host memory
import nvmeof
with nvmeof.Controller.connect(
"192.0.2.20",
"nqn.2026-07.io.example:storage",
source="192.0.2.21",
) as controller:
namespace = controller.namespace(1)
with controller.allocate(128 * 4096) as buffer:
namespace.read(buffer, slba=0, blocks=128)
payload = buffer.read()
controller.register(array_or_cpu_tensor) registers an existing contiguous
host allocation instead.
Direct GPU memory
import os
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
import torch
import nvmeof
tensor = torch.empty(128 * 4096, dtype=torch.uint8, device="cuda:0")
with nvmeof.Controller.connect(
"192.0.2.20", "nqn.2026-07.io.example:storage"
) as controller:
namespace = controller.namespace(1)
with controller.register_gpu(tensor) as gpu_mr:
# Target NVMe -> target RDMA WRITE -> local GPU memory.
# Namespace.read flushes completed GPUDirect writes before returning.
with torch.cuda.device(tensor.device):
namespace.read(gpu_mr, slba=0, blocks=128)
# Local GPU memory -> target RDMA READ -> target NVMe.
# Namespace.write synchronizes the current CUDA context first.
with torch.cuda.device(tensor.device):
namespace.write(gpu_mr, slba=1024, blocks=128)
namespace.flush()
The CUDA context that owns the tensor must be current while issuing GPU I/O. The registered MR must be closed before its controller.
source is optional. Set it to an address on the intended initiator HCA when
the host has multiple RDMA NICs. This makes an NVMe -> target NIC -> initiator
NIC -> GPU route explicit and prevents route selection from silently choosing
an HCA with poor GPU PCIe locality.
Reads and writes larger than the target's MDTS are split into multiple NVMe commands while retaining direct placement in the same registered buffer. The target used for the repository benchmarks advertises a 1 MiB MDTS; 4, 16, and 64 MiB GPU tensors were verified end to end.
Scope
The first implementation provides dynamic controller connection, controller enablement, Identify Controller/Namespace, one I/O queue, synchronous and low-level asynchronous command submission, block read/write splitting, and flush. It deliberately does not claim filesystem semantics, multipath, reconnect, keep-alive, protection information, authentication, or target functionality. KATO is therefore negotiated as zero.
Real-target tests use these environment variables:
| Variable | Default | Meaning |
|---|---|---|
NVME4PY_TARGET |
unset | Target hostname or IP; required to enable integration tests. |
NVME4PY_SUBSYSTEM_NQN |
unset | Target subsystem NQN; required to enable integration tests. |
NVME4PY_SOURCE |
unset | Optional local initiator IP/HCA binding. |
NVME4PY_NSID |
1 |
Namespace ID used by integration tests. |
NVME4PY_DESTRUCTIVE |
unset | Must equal 1 to enable the write/read GPU round trip. Use only with a disposable namespace. |
NVME4PY_TEST_SLBA |
0 |
Starting LBA overwritten by the destructive test. |
Measured multi-QP bandwidth, latency, QP scaling, and PCIe locality results
are in BENCHMARKS.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nvmeof-2026.8.4.tar.gz.
File metadata
- Download URL: nvmeof-2026.8.4.tar.gz
- Upload date:
- Size: 21.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d18ad1764cf6a9247e6f1317a2daa52737827ba18ca3dc7f7488586bbb86fca
|
|
| MD5 |
b4f62586f19a1997fa8671bf2c2f2f3d
|
|
| BLAKE2b-256 |
5eb399958607cb9776b9f4399d96f6970db56ca85ffd2f09bbb17401031bb22f
|
Provenance
The following attestation bundles were made for nvmeof-2026.8.4.tar.gz:
Publisher:
publish_nvmeof.yml on d4l3k/rdma4py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nvmeof-2026.8.4.tar.gz -
Subject digest:
9d18ad1764cf6a9247e6f1317a2daa52737827ba18ca3dc7f7488586bbb86fca - Sigstore transparency entry: 2339675061
- Sigstore integration time:
-
Permalink:
d4l3k/rdma4py@6a4a9cea475fa27495a03b74bee91959edeeb9ad -
Branch / Tag:
refs/heads/main - Owner: https://github.com/d4l3k
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_nvmeof.yml@6a4a9cea475fa27495a03b74bee91959edeeb9ad -
Trigger Event:
schedule
-
Statement type:
File details
Details for the file nvmeof-2026.8.4-py3-none-any.whl.
File metadata
- Download URL: nvmeof-2026.8.4-py3-none-any.whl
- Upload date:
- Size: 18.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d068e11fa261844341fe2443ecdf9b7feec1899dbae1735ad497fcd1af46772a
|
|
| MD5 |
768d0a6872a720e80cfad76e9f2195f5
|
|
| BLAKE2b-256 |
bf3405d0c40d1ebe16d73da4e7c1b35263e5f120f857a8205a153b7668ca85b2
|
Provenance
The following attestation bundles were made for nvmeof-2026.8.4-py3-none-any.whl:
Publisher:
publish_nvmeof.yml on d4l3k/rdma4py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nvmeof-2026.8.4-py3-none-any.whl -
Subject digest:
d068e11fa261844341fe2443ecdf9b7feec1899dbae1735ad497fcd1af46772a - Sigstore transparency entry: 2339675068
- Sigstore integration time:
-
Permalink:
d4l3k/rdma4py@6a4a9cea475fa27495a03b74bee91959edeeb9ad -
Branch / Tag:
refs/heads/main - Owner: https://github.com/d4l3k
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_nvmeof.yml@6a4a9cea475fa27495a03b74bee91959edeeb9ad -
Trigger Event:
schedule
-
Statement type: