rdma-verbs について
libibverbs による RDMA プログラミングを Agent 向けに解説し、デバイス設定、接続、データ操作を扱うガイドです。低遅延ネットワークの開発や、接続・完了通知・性能の問題調査に役立ちます。
主な機能
- 01libibverbs のデバイスとキュー設定
- 02片側・両側 RDMA 操作
- 03RC、UC、UD のトランスポート
- 04RoCE と InfiniBand の設定
- 05perftest による測定と Rust バインディング
活用シーン
- 01ストレージやデータベース向け低遅延ネットワークの構築
- 02片側 RDMA によるリモートメモリーアクセス
- 03Ethernet 上の RoCE 設定
- 04RDMA 接続や完了通知のエラー調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill rdma-verbsインストール後、Claude Code で/rdma-verbsを入力して読み込まれたか確認します。
詳細
RDMA Verbs
目的
libibverbs を使った RDMA プログラミングをエージェント向けに解説します。一方向操作と双方向操作、RC/UC/UD トランスポート、デバイスのセットアップ(ibv_get_device_list、保護ドメイン、メモリ登録、完了キュー、キューペア)、ワークリクエストと完了通知、RoCE と InfiniBand、perftest によるベンチマーク、Rust の rdma-sys バインディングを扱います。
使用する場面
- 超低レイテンシのストレージやデータベースのネットワークを構築する場合
- リモートメモリアクセスで CPU を介さない(一方向 RDMA)場合
- Ethernet ファブリック上に RoCE を設定する場合
- perftest ツールでネットワークファブリックのベンチマークを行う場合
- MPI や独自の RPC システムに RDMA を統合する場合
- RDMA の接続エラーや完了エラーをデバッグする場合
ワークフロー
1. RDMA の概念
RDMA stack
├── Application (libibverbs)
├── Kernel RDMA driver (mlx5, rdma_rxe)
├── NIC/HCA hardware
└── Fabric (InfiniBand or RoCE/Ethernet)
Operation types
├── Two-sided: Send/Recv (both sides participate)
└── One-sided: RDMA Read/Write (remote CPU not involved)
トランスポート:
| 種類 | 信頼性 | 接続 | 用途 |
|---|---|---|---|
| RC(信頼性のある接続) | あり | 1:1 の QP ペア | 汎用 |
| UC(信頼性のない接続) | なし | 1:1 | マルチキャストのような用途 |
| UD(信頼性のないデータグラム) | なし | 多対多 | MPI、検出 |
2. デバイスの検出
# List RDMA devices
ibv_devices
ibv_devinfo
# RoCE link status
rdma link show
ibstat
# Perftest prerequisites
modprobe ib_umad
3. libibverbs の最小セットアップ
#include <infiniband/verbs.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int num_devices;
struct ibv_device **dev_list = ibv_get_device_list(&num_devices);
if (!dev_list || num_devices == 0) {
fprintf(stderr, "No RDMA devices\n");
return 1;
}
struct ibv_context *ctx = ibv_open_device(dev_list[0]);
struct ibv_pd *pd = ibv_alloc_pd(ctx);
char buf[4096];
struct ibv_mr *mr = ibv_reg_mr(pd, buf, sizeof(buf),
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
struct ibv_cq *cq = ibv_create_cq(ctx, 10, NULL, NULL, 0);
struct ibv_qp_init_attr qp_attr = {
.send_cq = cq,
.recv_cq = cq,
.cap = { .max_send_wr = 10, .max_recv_wr = 10,
.max_send_sge = 1, .max_recv_sge = 1 },
.qp_type = IBV_QPT_RC,
};
struct ibv_qp *qp = ibv_create_qp(pd, &qp_attr);
printf("QP num %u, MR lkey %u rkey %u\n",
qp->qp_num, mr->lkey, mr->rkey);
ibv_destroy_qp(qp);
ibv_dereg_mr(mr);
ibv_destroy_cq(cq);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
ibv_free_device_list(dev_list);
return 0;
}
gcc -o rdma_setup rdma_setup.c -libverbs
4. 接続のセットアップ(RC)
RC では、QP 情報(lid、gid、qp_num、psn)を帯域外で交換する必要があります。
// Simplified: exchange via TCP socket before RDMA
struct qp_info {
uint16_t lid;
uint32_t qpn;
uint32_t psn;
union ibv_gid gid;
};
// Modify QP to INIT → RTR → RTS states
struct ibv_qp_attr attr = { .qp_state = IBV_QPS_INIT, ... };
ibv_modify_qp(qp, &attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | ...);
// RTR: set path_mtu, dest_qp_num, rq_psn, ah_attr
// RTS: set sq_psn, timeout, retry_cnt
接続管理を簡略化するには、rdmacm(librdmacm)を使用します。
#include <rdma/rdma_cma.h>
// rdma_create_event_channel, rdma_connect, rdma_accept
5. 送受信(双方向)
// Post receive
struct ibv_recv_wr recv_wr = {}, *bad_wr;
struct ibv_sge recv_sge = { .addr = (uint64_t)recv_buf, .length = 4096, .lkey = mr->lkey };
recv_wr.wr_id = 1;
recv_wr.sg_list = &recv_sge;
recv_wr.num_sge = 1;
ibv_post_recv(qp, &recv_wr, &bad_wr);
// Post send
struct ibv_send_wr send_wr = {}, *bad_send;
struct ibv_sge send_sge = { .addr = (uint64_t)send_buf, .length = msg_len, .lkey = mr->lkey };
send_wr.wr_id = 2;
send_wr.opcode = IBV_WR_SEND;
send_wr.sg_list = &send_sge;
send_wr.num_sge = 1;
ibv_post_send(qp, &send_wr, &bad_send);
// Poll completion
struct ibv_wc wc;
while (ibv_poll_cq(cq, 1, &wc) == 0);
if (wc.status != IBV_WC_SUCCESS)
fprintf(stderr, "WC error: %s\n", ibv_wc_status_str(wc.status));
6. RDMA Write(一方向)
struct ibv_send_wr wr = {}, *bad;
struct ibv_sge sge = { .addr = (uint64_t)local_buf, .length = len, .lkey = local_mr->lkey };
wr.wr_id = 3;
wr.opcode = IBV_WR_RDMA_WRITE;
wr.send_flags = IBV_SEND_SIGNALED;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.wr.rdma.remote_addr = remote_addr; // from peer exchange
wr.wr.rdma.rkey = remote_rkey;
ibv_post_send(qp, &wr, &bad);
リモート側の CPU は割り込まれず、データはリモートメモリに直接現れます。
7. RoCE と InfiniBand
| InfiniBand | RoCE | |
|---|---|---|
| 物理層 | 専用 IB ファブリック | Ethernet(ロスレス DCB/PFC) |
| LID/GID | 両方 | 主に GID(IPv6 に類似) |
| セットアップ | サブネットマネージャー | DCB 設定、PFC、ECN |
# RoCEv2 GID
cat /sys/class/infiniband/mlx5_0/ports/1/gids/3
8. perftest によるベンチマーク
# Server
ib_send_bw -d mlx5_0 -x 3
# Client
ib_send_bw -d mlx5_0 -x 3 <server_ip>
# Latency
ib_send_lat -d mlx5_0 <server_ip>
# RDMA write bandwidth
ib_write_bw -d mlx5_0 <server_ip>
9. Rust の rdma-sys
# Cargo.toml
rdma-sys = "0.1"
libibverbs を安全な抽象化でラップするか、より高水準の API を提供する async-rdma クレートを使用します。
よくある問題
| 症状 | 原因 | 対処法 |
|---|---|---|
ibv_reg_mr が失敗する | メモリ制限または権限の誤り | ulimit -l を確認し、アクセスフラグを設定します |
WC ステータスが rem_inv_req | rkey または addr が不正 | 再接続後に MR 情報を再交換します |
| QP が RTS への遷移に失敗する | PSN またはパスが不正 | lid/gid の一致とサブネットマネージャーを確認します |
| RoCE のパケットロス | スイッチで PFC が無効 | ロスレス Ethernet と DCQCN を有効にします |
| 帯域幅が低い | メッセージサイズが小さい | MTU を増やし、より大きな WR を使用します |
| デバイスが見つからない | ドライバーがロードされていない | modprobe mlx5_ib を実行し、ibv_devices を確認します |
関連スキル
skills/hpc/mpi— MPI は UCX/IB verbs 経由で RDMA を使用することがよくありますskills/async-io/dpdk— ユーザー空間ネットワーキングの代替手段skills/allocators/numa-programming— NUMA ローカルな MR 登録skills/profilers/linux-perf— CPU 側での RDMA 完了通知のポーリングskills/kernel/device-drivers— RDMA ドライバーの内部実装skills/virtualization/qemu-kvm— RDMA 用の SR-IOV VF パススルー
コメント
Markdown 対応