Validate the RDMA deployment

Prove that each layer of the RDMA stack works before you rely on it.

RDMA fails quietly. A node with the wrong binary, an inactive port, or a lossy fabric starts normally and serves every request over TCP. Work up the layers in order, because a failure at a lower layer makes every check above it meaningless.

Layer What it proves Section
1 The NIC presents an active RDMA port Check the adapter
2 GPU-to-NIC peer-to-peer DMA is allowed Check PCIe peer-to-peer
3 The fabric is lossless Check the fabric
4 The running binary is the RDMA build and it initialized Check the server
5 RDMA is carrying traffic Check the metrics
6 A client transfer used RDMA rather than HTTP Check an S3 transfer

1. Check the adapter

ibv_devinfo

Each usable port reports state: PORT_ACTIVE (4). Any other state, or no device at all, means the server falls back to HTTP for every transfer.

List the RDMA links and their netdev bindings:

rdma link show

2. Check PCIe peer-to-peer

S3 over RDMA only
Skip this layer if you are running inter-node RDMA alone.

The bridges above the GPU and the NIC must report ACS redirect cleared:

sudo lspci -vvv -s <bridge-bdf> | grep ACSCtl

Look for ReqRedir- and CmpltRedir-. If either shows +, work through Clear PCIe ACS redirect.

Confirm the one-shot ran on the current boot rather than trusting systemctl is-enabled:

sudo journalctl -u disable-pcie-acs.service -b

3. Check the fabric

Inter-node RDMA on a RoCE fabric only
InfiniBand deployments can skip this layer.

Put the fabric under all-to-all load, then read the counters. The perftest package, available as perftest on Debian and Ubuntu and perftest on RHEL derivatives, provides ib_write_bw for a point-to-point baseline:

# On the receiving node
ib_write_bw -d mlx5_0

# On the sending node
ib_write_bw -d mlx5_0 <receiver-ip>

A point-to-point test does not reproduce incast, which is the pattern that exposes a lossy fabric. For an all-to-all load, run a write benchmark against the deployment itself with warp and watch the counters during it. See Benchmarking.

While the load runs, confirm the fabric pauses rather than drops:

ethtool -S <dev> | grep -iE 'prio3_pause'
grep -r . /sys/class/infiniband/<rdma_dev>/ports/1/hw_counters/ | \
    grep -iE 'packet_seq_err|local_ack_timeout_err'

Pause counters rising is the good signal. packet_seq_err and local_ack_timeout_err must stay flat. See Confirm losslessness is working.

4. Check the server

Confirm the binary is the RDMA build

/usr/local/bin/minio.rdma --version

The version banner includes this line only on the RDMA build:

Features: GPU-Direct RDMA

This proves the build and nothing else. It says nothing about the fabric, the adapter, or whether initialization succeeded.

Confirm the running service is that binary:

systemctl show minio --property=ExecStart

Confirm the libraries resolve

ldd /usr/local/bin/minio.rdma | grep -E "ibverbs|rdmacm|s3rdma|p2p_rdma"

Every line must resolve to a path. libs3rdma.so.0 and libp2p_rdma.so.0 come from /usr/lib/minio.

Confirm initialization succeeded

Inter-node RDMA logs a single definitive success line:

journalctl -u minio | grep "RDMA: internode initialized"
RDMA: internode initialized with 15 remote peer(s), 2 local NIC(s), primary listener 10.0.0.1:5555

The local NIC count in that line is also how you confirm how many rails the server detected.

Two lines precede it and are worth reading:

Log line Meaning
RDMA: inbound receive pool ready: <count> buffers x <size> = <total> pinned (memlock) The receive-buffer pool registered. Compare the total against your LimitMEMLOCK.
RDMA: internode transfer concurrency bounded to <n> MINIO_RDMA_CONCURRENCY took effect.

For the GPU-Direct path:

journalctl -u minio | grep "GPU-Direct"
Log line Meaning
MinIO RDMA Server listening on <address> The GPU-Direct server started.
RDMA: GPU-Direct S3 server disabled (cuObjServer init failed) Initialization failed. The server runs, but every RDMA request is declined.
RDMA: GPU-Direct bandwidth limited to <n> B/s per direction --api-bandwidth is pacing RDMA transfers.

One line signals a degraded but working state:

RDMA: sender buffer registration failed (falling back to per-write reg): <error>

The node still transfers over RDMA, but registers memory on every write instead of reusing pre-registered buffers. Throughput suffers. Treat it as a fault to investigate.

5. Check the metrics

Scrape the two RDMA metric groups:

curl http://localhost:9000/minio/metrics/v3/api/rdma
curl http://localhost:9000/minio/metrics/v3/system/network/internode/rdma
To prove Watch
S3 over RDMA is carrying traffic minio_api_rdma_read_bytes_total and minio_api_rdma_write_bytes_total increase
Inter-node RDMA is carrying traffic minio_system_network_internode_rdma_write_bytes_total increases during writes
Every rail is in use minio_system_network_internode_rdma_nic_inflight_writes reports a series per nic label
RDMA is silently falling back to TCP minio_system_network_internode_rdma_pool_fallbacks_total increases
The fabric is unhealthy minio_system_network_internode_rdma_errors_total increases, or ..._nic_credit_waits_total and ..._nic_writes_throttled_total climb

A rising pool_fallbacks_total is not an error. It means a PUT shard arrived while the receive-buffer pool was busy, or was larger than one slab, and the transfer used TCP instead. Sustained growth means the pool is undersized for the workload. See Receive-buffer pool.

For the full metric list, see Metrics version 3.

6. Check an S3 transfer

A client proves RDMA served its request by reading the response headers.

Header Meaning
x-amz-rdma-reply: 200 Served over RDMA
x-amz-rdma-reply: 206 Served over RDMA, ranged or part request
x-amz-rdma-reply: 501 Declined. The response body is an S3 error, not the object.

On a successful RDMA transfer the server also sets Content-Length: 0, because the object bytes travelled outside the HTTP response.

Confirm from the server side as well. Read the counter matching the transfer direction before and after, and check that it increased: minio_api_rdma_read_ops_total for a GET, minio_api_rdma_write_ops_total for a PUT or part upload.

A 501 reply does not mean the server served the object over HTTP. The server returns an S3 error, and the client is responsible for retrying without the x-amz-rdma-token header. The MinIO SDKs handle this automatically. See S3 over RDMA.

If a layer fails

See Troubleshoot RDMA.