---
title: RDMA (Remote Direct Memory Access)
url: https://doc.liz6.com/linux-kernel/06-network-subsystem/05-RDMA
locale: zh
area: linux-kernel
tags:
- linux-kernel
- 网络子系统
date: 2026-06-30
modified: 2026-07-11
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 允许一台机器直接读写另一台机器的内存，**绕过远程 CPU 和内核**。延迟从传统 TCP/IP 的 ~50μs 降到 ~1μs，同时 CPU 零参与数据传输。Linux 通过 `ib_core` + 厂商驱动 (mlx5, qedr, hns) 提供统一的 RDMA 接口。

## 三种传输

| | 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 的缓冲区 (先 post 缓冲, 收到 SEND 后填充)
CQ: 完成通知 (操作完成后硬件写 CQE)

QP 状态机:
  RESET → INIT → RTR (Ready To Receive) → RTS (Ready To Send)
```

## Memory Region (MR)

```c
// RDMA 硬件直接写远端内存 → 需要内存"注册" (pinning)
// 注册: ibv_reg_mr() → 硬件锁定物理页 + 生成 access key (rkey/lkey)
// 
// 为什么需要注册?
//   RDMA HCA 旁路了内核 → 不能依赖 CPU 页表做地址转换
//   → 需要物理地址的直接映射 + 锁定的页面 (不能 swap/page fault)

// 按需分页 (ODP) / 隐式 MR (IMR):
//   减少注册开销 → 按需 pin/unpin
```

## Verbs API

```c
// 用户态: libibverbs

// 找到设备
ibv_get_device_list()

// 创建 QP
ibv_create_qp(pd, &qp_init_attr)

// Post work request (发送)
ibv_post_send(qp, &wr, &bad_wr)
// RDMA_WRITE: 直接写远端内存 (最常用)
// RDMA_READ:  直接读远端内存
// SEND:       发消息 (远端需要 pre-post RECV)

// Completion
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">网卡</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">网卡</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 直连网卡,数据面完全绕开内核协议栈,延迟从 ~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*
