Low-level Pythonic bindings for libibverbs (RDMA), with GPUDirect support
Project description
ibverbs
Low-level, Pythonic bindings for libibverbs (RDMA), designed as a foundation for building high-performance RDMA libraries in Python — including GPUDirect transfers to/from GPU memory.
The bindings are a thin, faithful wrapper over the verbs API (device, PD, MR,
CQ, QP, SRQ, AH, work requests, completions, async events) plus a small,
optional set of RC connection helpers. They are written in Cython so the data
path (post_send / post_recv / poll) compiles to direct C calls and
releases the GIL, and so the static inline verbs fast-path functions are
called correctly (they can't be reached through dlsym).
- No runtime dependencies. Only libibverbs, which is
dlopened at import. - No torch / CUDA linkage. GPUDirect works by registering an integer device address or an exported dma-buf fd; CUDA stays entirely in your code.
- One
abi3wheel for all of CPython 3.9+ on Linux.
Portability
The extension does not link libibverbs. It is compiled against the
rdma-core headers (for struct layouts and the static inline data-path verbs)
but resolves the exported verbs at import time with dlopen/dlsym. As a
result:
- The compiled module's only
NEEDEDlibrary islibc— no external dependency forauditwheel, so a single manylinux wheel is portable across distros. - It is built against the CPython Limited API (abi3), so one wheel works on CPython 3.9 through 3.14+ — no per-version builds.
- A missing
libibverbsyields a cleanImportError, not a loader crash. - Newer verbs are optional:
ibv_reg_dmabuf_mr(rdma-core ≥ 34) is loaded if present and only errors if you actually callreg_dmabuf_mr, so the wheel still imports on older systems.
At runtime you only need libibverbs.so.1 (any rdma-core from the last
several years). The data path (post_send/poll/…) stays compiled inline and
dispatches through the provider op table, so dlopen costs nothing on the hot
path.
Requirements
- Linux with an RDMA-capable NIC (tested on Mellanox/NVIDIA mlx5, RoCEv2).
- Runtime:
libibverbs.so.1(rdma-core—libibverbs1on Debian/Ubuntu,libibverbson RHEL/Fedora). No compiler or headers needed to use a wheel. - Build from source only: a C compiler, Cython, and the
rdma-coredevelopment headers (libibverbs-dev/rdma-core-devel).
Install
pip install ibverbs # prebuilt abi3 manylinux wheel (once published)
Building from source (needs the rdma-core dev headers + a compiler):
pip install "Cython>=3.0" "setuptools>=77" wheel
pip install ./ibverbs # or: pip install -e ./ibverbs
Quickstart
import ibverbs as ib
# 1. Open a device and set up resources.
dev = ib.get_device_list()[0]
ctx = dev.open()
pd = ctx.alloc_pd()
cq = ctx.create_cq(64)
# 2. Register memory (host or GPU address — any integer VA works).
import numpy as np
buf = np.zeros(4096, dtype=np.uint8)
access = ib.AccessFlags.LOCAL_WRITE | ib.AccessFlags.REMOTE_WRITE | ib.AccessFlags.REMOTE_READ
mr = pd.reg_mr(buf.ctypes.data, buf.nbytes, access)
# 3. Create a reliable-connected QP.
qp = pd.create_qp(ib.QPInitAttr(send_cq=cq, recv_cq=cq, qp_type=ib.QPType.RC))
# 4. Exchange connection info with the peer out-of-band, then connect.
port = 1
port_attr = ctx.query_port(port)
gid = ctx.query_gid(port, gid_index) # pick a routable RoCEv2 GID
local = ib.local_qp_info(qp, port_attr, gid, port=port, psn=0)
# ... send local.to_bytes() to peer, receive remote_bytes ...
remote = ib.QPInfo.from_bytes(remote_bytes)
ib.connect_rc(qp, remote, port=port, sgid_index=gid_index, access=access)
# 5. Post an RDMA write and reap the completion.
qp.post_send(ib.SendWR(
wr_id=1, sg_list=[ib.SGE(mr, 4096)], opcode=ib.WROpcode.RDMA_WRITE,
send_flags=ib.SendFlags.SIGNALED, remote_addr=peer_addr, rkey=peer_rkey))
for wc in cq.poll(16):
wc.raise_for_status()
Every resource is a context manager and frees its handle on close() /
garbage collection; children hold references to their parents, so destruction
order is always safe.
GPUDirect with torch tensors
The library never imports torch or links CUDA. The optional ibverbs.cuda
helper (which only lazily dlopens libcuda) registers a CUDA tensor for RDMA
in one call — handling the dma-buf export and page alignment for you:
import os
# torch's CUDA memory must be VMM-backed to be dma-buf exportable. Set this
# BEFORE torch initializes CUDA:
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
import torch
import ibverbs as ib
import ibverbs.cuda
src = torch.arange(4096, dtype=torch.float32, device="cuda:0")
dst = torch.zeros(4096, dtype=torch.float32, device="cuda:0")
access = ib.AccessFlags.LOCAL_WRITE | ib.AccessFlags.REMOTE_WRITE
src_mr = ib.cuda.register_tensor(pd, src, access) # retains src until close()
dst_mr = ib.cuda.register_tensor(pd, dst, access)
# RDMA-write one GPU buffer into another, with no host staging on the data path.
torch.cuda.synchronize(src.device) # source-producing CUDA work must be done
qp.post_send(ib.SendWR(
wr_id=1, sg_list=[src_mr.sge()], opcode=ib.WROpcode.RDMA_WRITE,
send_flags=ib.SendFlags.SIGNALED,
remote_addr=dst_mr.addr, rkey=dst_mr.rkey))
for wc in qp.send_cq.poll(16):
wc.raise_for_status()
# On the receiver, after the peer has signaled that its write is complete,
# order the inbound NIC writes before launching CUDA work that consumes dst.
with torch.cuda.device(dst.device):
ib.cuda.flush_gpudirect_writes()
GpuMR wraps the MR with the correct device address (ibv_mr.addr is not
meaningful for dma-buf MRs), retains the tensor allocation until close(), and
exposes .sge(), .addr, .lkey, .rkey.
CUDA work and NIC work are separate ordering domains. Synchronize the stream
that produced an outbound tensor before posting it. For inbound SEND, RDMA
read, or RDMA write, wait for the corresponding completion or protocol-level
notification, then call flush_gpudirect_writes() in the destination CUDA
context before consuming the tensor. A one-sided RDMA write does not create a
remote CQ entry by itself; use write-with-immediate or an out-of-band message
to notify the receiver.
Under the hood there are two registration paths, chosen automatically:
# dma-buf fd (default; no kernel module needed):
mr = pd.reg_dmabuf_mr(offset, length, iova=device_va, fd=dmabuf_fd, access=access)
# raw device pointer (requires the nvidia_peermem kernel module):
mr = pd.reg_mr(tensor.data_ptr(), nbytes, access)
For a host (CPU) torch tensor or numpy array, ib.reg_tensor(pd, tensor, access) registers it directly and retains the allocation. Both tensor helpers
require contiguous, non-empty tensors; split any single SGE larger than
2**32 - 1 bytes into multiple entries. tests/test_gpudirect.py performs real
GPU-to-GPU RDMA writes, reads, and sends verified with torch.equal.
Feature coverage
| Area | Supported |
|---|---|
| Device / port / GID query | ✅ get_device_list, Context.query_device/query_port/query_gid |
| Protection domains | ✅ alloc_pd |
| Memory regions | ✅ reg_mr, reg_dmabuf_mr (GPUDirect) |
| Completion queues | ✅ create_cq, poll, comp channels + req_notify/ack_events |
| Queue pairs | ✅ RC / UC / UD; modify, query, to_init/to_rtr/to_rts |
| Work requests | ✅ SEND(/_IMM), RDMA_WRITE(/_IMM), RDMA_READ, ATOMIC_CMP_AND_SWP, ATOMIC_FETCH_AND_ADD, scatter/gather, inline/signaled/fenced/solicited flags |
| Shared receive queues | ✅ create_srq, post_recv, modify, query |
| Address handles | ✅ create_ah (UD) |
| Async events | ✅ get_async_event / ack_async_event, async_fd |
| Connection helpers | ✅ QPInfo, local_qp_info, connect_rc |
Out of scope for v1 (candidates for later): the extended ibv_wr_* / qp_ex
post API, device memory (ibv_alloc_dm), memory windows, and flow steering.
Testing
The suite exercises real hardware and skips features the host lacks:
pip install -e "./ibverbs[test,gpu]" # pytest, numpy, torch
cd ibverbs && pytest -rs # -rs shows skip reasons
pytest -m "not gpu" # skip GPUDirect tests
pytest -m integration # only real-hardware tests
Markers: integration (needs an RDMA NIC), gpu (needs CUDA + torch).
License
BSD-3-Clause. See the repository LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 ibverbs-2026.7.17.tar.gz.
File metadata
- Download URL: ibverbs-2026.7.17.tar.gz
- Upload date:
- Size: 314.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be3791413bb3f8732ec438bc9355d524396f6b0b845439866e247ced7ba4bdf5
|
|
| MD5 |
4bc9e55ac8c35dc1a3744e71b2153780
|
|
| BLAKE2b-256 |
3b7fd6db832a3e649a74c5ac971697ee487721e90a8af858338ce6e6ee1b91b1
|
Provenance
The following attestation bundles were made for ibverbs-2026.7.17.tar.gz:
Publisher:
publish.yml on d4l3k/rdma4py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ibverbs-2026.7.17.tar.gz -
Subject digest:
be3791413bb3f8732ec438bc9355d524396f6b0b845439866e247ced7ba4bdf5 - Sigstore transparency entry: 2193227003
- Sigstore integration time:
-
Permalink:
d4l3k/rdma4py@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Branch / Tag:
refs/tags/v2026.7.17 - Owner: https://github.com/d4l3k
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Trigger Event:
push
-
Statement type:
File details
Details for the file ibverbs-2026.7.17-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.
File metadata
- Download URL: ibverbs-2026.7.17-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
- Upload date:
- Size: 1.0 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
520b173394682b24e998ed90cbb029b0bacc5525e197ea3a88c9ab045723747a
|
|
| MD5 |
bef0b9f4836e496c08458d82bbc9e2a2
|
|
| BLAKE2b-256 |
23c9f39188a523ca2f5611332e740ef9dd1826e5e574ad74edb0f347803e1785
|
Provenance
The following attestation bundles were made for ibverbs-2026.7.17-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl:
Publisher:
publish.yml on d4l3k/rdma4py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ibverbs-2026.7.17-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl -
Subject digest:
520b173394682b24e998ed90cbb029b0bacc5525e197ea3a88c9ab045723747a - Sigstore transparency entry: 2193227005
- Sigstore integration time:
-
Permalink:
d4l3k/rdma4py@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Branch / Tag:
refs/tags/v2026.7.17 - Owner: https://github.com/d4l3k
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Trigger Event:
push
-
Statement type:
File details
Details for the file ibverbs-2026.7.17-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: ibverbs-2026.7.17-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 1.0 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
392133388adb89404c165a2f08c9fe1e3538094e67eadbd09ca3c5a079eb71a4
|
|
| MD5 |
2c48aadd1850e1a6acfbff80d57190d7
|
|
| BLAKE2b-256 |
373ee15ccae25f51390e74e9e4bb38cc9ab9c6eeb225f830f0faff8b6b18332d
|
Provenance
The following attestation bundles were made for ibverbs-2026.7.17-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl:
Publisher:
publish.yml on d4l3k/rdma4py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ibverbs-2026.7.17-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl -
Subject digest:
392133388adb89404c165a2f08c9fe1e3538094e67eadbd09ca3c5a079eb71a4 - Sigstore transparency entry: 2193227007
- Sigstore integration time:
-
Permalink:
d4l3k/rdma4py@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Branch / Tag:
refs/tags/v2026.7.17 - Owner: https://github.com/d4l3k
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5de8f3c90e20466bc4737980ee9850be1fab56e -
Trigger Event:
push
-
Statement type: