---
title: RDMA (Remote Direct Memory Access)
url: https://doc.liz6.com/ja/linux-kernel/06-network-subsystem/05-RDMA
locale: ja
area: linux-kernel
tags:
- linux-kernel
- network-subsystem
date: 2026-06-30
modified: 2026-07-16
description: '概要: RDMA アーキテクチャ → InfiniBand/RoCE/iWARP → verbs API → Queue Pair → Memory Region → カーネルバイパス → Linux ネットワークスタックとの統合。カーネルバージョン: 3.x ~ 6.x'
---

# RDMA (Remote Direct Memory Access)

> 概要: RDMA アーキテクチャ → InfiniBand/RoCE/iWARP → verbs API → Queue Pair → Memory Region → カーネルバイパス → Linux ネットワークスタックとの統合
> カーネルバージョン: 3.x ~ 6.x

## 概要

RDMA を使用すると、1台のマシンが別のマシンのメモリに直接読み書きでき、**リモート側のCPUとカーネルをバイパス**できます。レイテンシは従来の TCP/IP の約 50μs から約 1μs に短縮され、データ転送には CPU がゼロ関与します。Linux は `ib_core` とベンダードライバ (mlx5, qedr, hns) を通じて、統一された RDMA インターフェースを提供します。

## 3つのトランスポート

| | InfiniBand | RoCEv2 | iWARP |
|---|---|---|---|
| ネットワーク層 | IB L2/L3 | UDP/IP (dst port 4791) | TCP/IP |
| ハードウェア | IB HCA | 統合イーサネットカード | 統合イーサネットカード |
| 依存関係 | IB スイッチ | DCB/PFC (損失なしイーサネット) | 標準 TCP オフロード |
| カーネルサポート | `ib_core` | `ib_core` + `rdma_rxe`(SW) | `iw_cm` |

## コア抽象: Queue Pair (QP)

```
各 QP = Send Queue (SQ) + Receive Queue (RQ) + Completion Queue (CQ)

SQ: ローカル側から開始される RDMA 操作 (SEND, RDMA_WRITE, RDMA_READ)
RQ: リモート側の SEND を待つためのバッファ (事前にバッファをポストし、SEND 受信後にデータが充填される)
CQ: 完了通知 (操作完了時にハードウェアが CQE を書き込む)

QP の状態遷移:
  RESET → INIT → RTR (Ready To Receive) → RTS (Ready To Send)
```

## Memory Region (MR)

```c
// RDMA ハードウェアはリモートメモリに直接書き込むため、メモリを「登録」(ピン留め) する必要がある
// 登録: ibv_reg_mr() → ハードウェアが物理ページをロックし、アクセスキー (rkey/lkey) を生成する
// 
// なぜ登録が必要なのか?
//   RDMA HCA はカーネルをバイパスするため、CPU のページテーブルによるアドレス変換に依存できない
//   → 物理アドレスへの直接マッピング + ロックされたページ (スワップやページフォルト不可) が必要

// 必要に応じたページング (ODP) / 暗黙的 MR (IMR):
//   登録オーバーヘッドを削減し、必要に応じて pin/unpin を行う
```

## Verbs API

```c
// ユーザー空間: libibverbs

// デバイスの取得
ibv_get_device_list()

// QP の作成
ibv_create_qp(pd, &qp_init_attr)

// ワークリクエストのポスト (送信)
ibv_post_send(qp, &wr, &bad_wr)
// RDMA_WRITE: リモートメモリに直接書き込み (最も一般的)
// RDMA_READ:  リモートメモリから直接読み込み
// SEND:       メッセージを送信 (リモート側は事前に RECV をポストしておく必要がある)

// 完了処理
ibv_poll_cq(cq, num_entries, &wc)  // CQE を読み取る
```

## カーネルバイパスと Linux 統合

<svg viewBox="0 0 720 380" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="カーネルバイパスの比較: 従来の TCP と RDMA パス、および RDMA 接続確立には依然としてカーネルの関与が必要">
  <defs>
    <marker id="rdmaArrow" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="380" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">カーネルバイパスの比較: データパスはカーネルを迂回するが、接続確立はカーネルに依存</text>

  <text x="48" y="84" font-size="13" font-weight="600" fill="#64748b">従来の TCP</text>
  <text x="48" y="100" font-size="11" fill="#94a3b8">カーネル経由</text>
  <rect x="130" y="66" width="70" height="40" rx="5" fill="#e2e8f0"/><text x="165" y="90" text-anchor="middle" font-size="11" fill="#334155">app</text>
  <line x1="200" y1="86" x2="222" y2="86" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="222" y="66" width="80" height="40" rx="5" fill="#e2e8f0"/><text x="262" y="90" text-anchor="middle" font-size="11" fill="#334155">socket</text>
  <line x1="302" y1="86" x2="324" y2="86" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="324" y="66" width="80" height="40" rx="5" fill="#e2e8f0"/><text x="364" y="90" text-anchor="middle" font-size="11" fill="#334155">TCP/IP</text>
  <line x1="404" y1="86" x2="426" y2="86" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="426" y="66" width="100" height="40" rx="5" fill="#e2e8f0"/><text x="476" y="90" text-anchor="middle" font-size="11" fill="#334155">netdevice</text>
  <line x1="526" y1="86" x2="548" y2="86" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="548" y="66" width="60" height="40" rx="5" fill="#e2e8f0"/><text x="578" y="90" text-anchor="middle" font-size="11" fill="#334155">NIC</text>

  <text x="48" y="178" font-size="13" font-weight="700" fill="#0f766e">RDMA</text>
  <text x="48" y="194" font-size="11" fill="#14b8a6">カーネルをバイパス</text>
  <rect x="130" y="160" width="70" height="40" rx="5" fill="#f0fdfa" stroke="#99f6e4"/><text x="165" y="184" text-anchor="middle" font-size="11" fill="#115e59">app</text>
  <line x1="200" y1="180" x2="222" y2="180" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="222" y="160" width="70" height="40" rx="5" fill="#f0fdfa" stroke="#99f6e4"/><text x="257" y="184" text-anchor="middle" font-size="11" fill="#115e59">verbs</text>
  <line x1="292" y1="180" x2="314" y2="180" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="314" y="160" width="110" height="40" rx="5" fill="#f0fdfa" stroke="#99f6e4"/><text x="369" y="184" text-anchor="middle" font-size="11" fill="#115e59">ユーザー空間ドライバ</text>
  <line x1="424" y1="180" x2="446" y2="180" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="446" y="160" width="60" height="40" rx="5" fill="#f0fdfa" stroke="#99f6e4"/><text x="476" y="184" text-anchor="middle" font-size="11" fill="#115e59">NIC</text>
  <text x="516" y="184" font-size="11" fill="#0f766e">(カーネルを完全にバイパス!)</text>

  <line x1="60" y1="218" x2="660" y2="218" stroke="#e2e8f0" stroke-width="1"/>

  <text x="60" y="246" font-size="13" font-weight="700" fill="#9a3412">ただし、接続確立には依然としてカーネルが必要: RDMA CM は完全なフローを実行する</text>
  <rect x="90" y="256" width="170" height="36" rx="5" fill="#ffedd5"/><text x="175" y="278" text-anchor="middle" font-size="10.5" fill="#9a3412">RDMA CM (接続管理)</text>
  <line x1="260" y1="274" x2="280" y2="274" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="280" y="256" width="200" height="36" rx="5" fill="#ffedd5"/><text x="380" y="278" text-anchor="middle" font-size="10.5" fill="#9a3412">IP アドレス解決 + ルーティング検索</text>
  <line x1="480" y1="274" x2="500" y2="274" stroke="#475569" stroke-width="1.6" marker-end="url(#rdmaArrow)"/>
  <rect x="500" y="256" width="140" height="36" rx="5" fill="#ffedd5"/><text x="570" y="278" text-anchor="middle" font-size="10.5" fill="#9a3412">RC QP の確立</text>

  <rect x="60" y="304" width="600" height="54" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="76" y="326" font-size="12.5" fill="#3730a3">RDMA は verbs を介して NIC に直接接続し、データパスはカーネルプロトコルスタックを完全に迂回するため、レイテンシは約 50μs から約 1μs に短縮されます;</text>
  <text x="76" y="346" font-size="12.5" fill="#3730a3">ただし、接続確立フェーズ (RDMA CM) では、アドレス解決とルーティング検索のために依然としてカーネルを経由する必要があり、「ゼロカーネル関与」ではありません。</text>
</svg>

## 参考

- **ソースコード**: `drivers/infiniband/core/`, `drivers/infiniband/hw/mlx5/`, `include/rdma/`
- **ドキュメント**: `Documentation/infiniband/`
- **LWN**: "RDMA and the Linux kernel"

*キーワード: RDMA, InfiniBand, RoCE, QP, Memory Region, verbs, kernel bypass, ib_core*
