0%

Getting Started with InfiniBand

函数

ibv_fork_init

文档
ibv_fork_init

模板: int ibv_fork_init(void)

输入参数: 无

输出参数: 无

返回值: 0 on success, -1 on error. If the call fails, errno will be set to indicate the
reason for the failure.

描述: ibv_fork_init 初始化 libverbs 的数据结构来安全地处理 fork() 并避免数据损坏,不论
fork() 是被显式调用还是隐式调用(比如在 system() 中被调用)。如果所有的父进程总是阻塞直至所有的
子进程结束或使用 exec() 改变地址空间,那么 ibv_fork_init 可以不被调用。

该函数在支持 madviseMADV_DONTFORK 标记的 Linux 内核(2.6.17 或更高)上可以工作。

设置环境变量 RDMAV_FORK_SAFEIBV_FORK_SAFE 环境变量为任意值,有着与 ibv_fork_init 相同的效
果。

设置 RDMAV_HUGEPAGES_SAFE 为任意值,以告诉库需要检查内核为内存域(memory regions)使用的底层内存页
的大小。如果应用程序直接或通过库(如 libhugtlbfs )间接使用大内存页(博主注:即大于 4KB)时,该环境
变量是必须的。(博主注:ibv_fork_init 将检查 RDMAV_HUGEPAGES_SAFE

调用 ibv_fork_init 将降低性能,因为每个内存注册都将有一个额外的系统调用和分配附加的内存以追踪内存
域(memory regions)。确切的性能损失取决于工作负载,通常不会很大。

设置 RDMAV_HUGEPAGES_SAFE 会为所有的内存注册增加更多的开销。

文档

Documentation: RDMA Aware Networks Programming User Manual v1.6

Local Documentation

Sun Network QDR InfiniBand Gateway Switch Topic Set

RDMA 知乎专栏

用户态的 Verbs API 手册跟代码在一个仓库维护,手册地址
https://github.com/linux-rdma/rdma-core/tree/master/libibverbs/man

有很多在线的 man page 网站可以查阅这些接口的说明,比如官方的连接
https://man7.org/linux/man-pages/man3/ibv_post_send.3.html

也有一些其他非官方网页,支持在线搜索:https://linux.die.net/man/3/ibv

查阅系统 man page 如果你使用的商用 OS 安装了 rdma-core 或者 libibverbs 库,那么可以直接用 man 命令查
询接口:

1
man ibv_post_send

查询 Mellanox 的编程手册
RDMA Aware Networks Programming User Manual Rev 1.7
,最新版是 2015 年更新的。该手册写的比较详尽,并且附有示例程序,但是可能与最新的接口有一些差异
。Mellanox VPI®(Virtual Procotol Interconnect)架构为同时支持 InfiniBand 和以太网语义的网络适配器和
交换机提供高性能、低延迟和可靠的方法。

Book:
Linux Kernel Networking - Implementation and Theory

Dotan’s blog: Dotan Barak, an InfiniBand Expert. Dotan is a Senior
Software Manager at Mellanox Technologies working on RDMA Technologies.

性能分析工具(profiling)

Blog:
Tips and tricks to optimize your RDMA code

libibprof

IB 简介

RDMA - Remote Direct Memory Access 远程直接内存存取。

InfiniBand 是一种高性能计算机网络通信标准,它具有极高的吞吐量和极低的延迟。如果您需要使用 InfiniBand
进行编程,您需要使用支持 InfiniBand 的编程语言(如 C++)来编写代码。

机构和组织:

OFA: Open Fabrics Alliance.

IBTA: InfiniBand Trade Association.

概念

  • CQ - Complete Queue 完成队列
  • WQ - Work Queue 工作队列
  • WR - Work Request 工作请求
  • QP - Queue Pairs 队列对(Send-Receive)
  • SQ - Send Queue 发送队列
  • RQ - Receive Queue 接收队列
  • PD - Protection Domain 保护域,将 QP 和 MR 结合在一起
  • MR - Memory Region 内存区域。一块经注册过的且本地网卡可以读写的内存区域。包含 R_Key 和 L_Key。
  • SGE - Scatter/Gather Elements 分散/聚集元素。
  • R_Key - Remote Key
  • L_Key - Local Key
  • CA - (Host) Channel Adapter, an inifiniband network interface card.
  • NIC - Network Interface Card 网卡。
  • LID - Local Identifier.
  • CM - Connection Manager.

其他常见缩写:

  • RC - reliable connected.
  • SCSI - Small Computer System Interface 小型计算机系统接口。
  • SRP - SCSI RDMA Protocol. / Secure Remote Password.

博客:https://blog.51cto.com/liangchaoxi/4044818

安装

InfiniBand 和 RDMA 相关软件包

sudo apt-get install infiniband-diags
sudo apt install ibverbs-utils

API

以下是一些支持 InfiniBand 的 C++库:

Infinity:这是一个轻量级的 C++ RDMA 库,用于 InfiniBand 网络。它提供了对两侧(发送/接收)和单侧(读/
写/原子)操作的支持,并且是一个简单而强大的面向对象的 ibVerbs 抽象。该库使用户能够构建使用 RDMA 的复
杂应用程序,而不会影响性能1

OFED:这是一个开放式 Fabrics Enterprise Distribution,它提供了对 InfiniBand 和 RoCE(RDMA over
Converged Ethernet)技术的支持。OFED 提供了一组用户空间库和驱动程序,可用于构建支持 RDMA 的应用程
2

以下是使用 Infinity 库编写支持 InfiniBand 的 C++代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 创建新上下文
infinity::core::Context *context = new infinity::core::Context();

// 创建队列对
infinity::queues::QueuePairFactory *qpFactory = new infinity::queues::QueuePairFactory(context);
infinity::queues::QueuePair *qp = qpFactory->connectToRemoteHost(SERVER_IP, PORT_NUMBER);

// 创建并向网络注册缓冲区
infinity::memory::Buffer *localBuffer = new infinity::memory::Buffer(context, BUFFER_SIZE);

// 从远程缓冲区读取(单向)并等待完成
infinity::memory::RegionToken *remoteBufferToken = new infinity::memory::RegionToken(REMOTE_BUFFER_INFO);
infinity::requests::RequestToken requestToken(context);
qp->read(localBuffer, remoteBufferToken, &requestToken);
requestToken.waitUntilCompleted();

// 将本地缓冲区的内容写入远程缓冲区(单向)并等待完成
qp->write(localBuffer, remoteBufferToken, &requestToken);
requestToken.waitUntilCompleted();

// 将本地缓冲区的内容通过队列对发送(双向)并等待完成
qp->send(localBuffer, &requestToken);
requestToken.waitUntilCompleted();

// 关闭连接
delete remoteBufferToken;
delete localBuffer;
delete qp;
delete qpFactory;
delete context;

以下是使用 OFED 库编写支持 InfiniBand 的 C++代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 创建新上下文
struct ibv_context *context = ibv_open_device(*device);

// 创建完成端口
struct ibv_pd *pd = ibv_alloc_pd(context);

// 创建队列对
struct ibv_qp_init_attr qp_init_attr;
memset(&qp_init_attr, 0, sizeof(qp_init_attr));
qp_init_attr.send_cq = cq;
qp_init_attr.recv_cq = cq;
qp_init_attr.qp_type = IBV_QPT_RC;
qp_init_attr.cap.max_send_wr = 1;
qp_init_attr.cap.max_recv_wr = 1;
qp_init_attr.cap.max_send_sge = 1;
qp_init_attr.cap.max_recv_sge = 1;
struct ibv_qp *qp = ibv_create_qp(pd, &qp_init_attr);

// 创建并向网络注册缓冲区
char *localBuffer = (char *)malloc(BUFFER_SIZE);
struct ibv_mr *mr = ibv_reg_mr(pd, localBuffer, BUFFER_SIZE, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE);

// 连接到远程主机
struct sockaddr_in remoteAddress;
memset(&remoteAddress, 0, sizeof(remoteAddress));
remoteAddress.sin_family = AF_INET;
remoteAddress.sin_port = htons(PORT_NUMBER);
inet_pton(AF_INET, SERVER_IP, &remoteAddress.sin_addr);
struct rdma_cm_id *cmId;
rdma_create_id(*eventChannel, &cmId, NULL, RDMA_PS_TCP);
rdma_resolve_addr(cmId, NULL, (struct sockaddr *)&remoteAddress, RESOLVE_TIMEOUT_MS);

// 等待连接完成
rdma_wait_event(*eventChannel, RDMA_CM_EVENT_ESTABLISHED);
rdma_ack_cm_event(cmEvent);

// 获取远程缓冲区信息
struct ibv_wc wc;
ibv_post_recv(qp, &recvWr, &badRecvWr);
do {
ibv_poll_cq(cq, 1, &wc);
} while (wc.status != IBV_WC_SUCCESS || wc.opcode != IBV_WC_RECV_RDMA_WITH_IMM || wc.imm_data != htonl(IMM_DATA));
remoteBufferInfo.rkey = ntohl(wc.imm_data >> 8);
remoteBufferInfo.vaddr = wc.wr_id;

// 将本地缓冲区的内容写入远程缓冲区(单向)
struct ibv_send_wr sendWr;
memset(&sendWr, 0, sizeof(sendWr));
sendWr.wr_id = 0;
sendWr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM;
sendWr.sg_list = &localSge;
sendWr.num_sge = 1;
sendWr.send_flags = IBV_SEND_SIGNALED;
sendWr.wr.rdma.remote_addr = remoteBufferInfo.vaddr;
sendWr.wr.rdma.rkey = remoteBufferInfo.rkey;
localSge.addr = (uintptr_t)localBuffer;
localSge.length = BUFFER_SIZE;
localSge.lkey = mr->lkey;
ibv_post_send(qp, &sendWr, &badSendWr);

// 关闭连接
ibv_dereg_mr(mr);
free(localBuffer);
ibv_destroy_qp(qp);
ibv_dealloc_pd(pd);
ibv_close_device(context);

Linux manual page

Command-Line

文档:https://docs.nvidia.com/networking/pages/viewpage.action?pageId=43719572

  • ibstat

  • ibhosts - 查看所有的 IB hosts。

  • ibnetdiscover - discover InfiniBand topology.

  • ibv_devices - list RDMA devices.

  • ibv_devinof - Print information about RDMA devices available for use from userspace.

  • ibv_rc_pingpong - Run a simple ping-pong test over InfiniBand via the reliable connected (RC)
    transport.

  • targetcli - administration shell for storage targets

    targetcli is a shell for viewing, editing, and saving the configuration of the kernel’s target
    subsystem, also known as LIO. It enables the administrator to assign local storage resources
    backed by either files, volumes, local SCSI devices, or ramdisk, and export them to remote systems
    via network fabrics, such as iSCSI or FCoE.

  • srp_daemon - Discovers and connects to InfiniBand SCSI RDMA Protocol (SRP) targets in an IB
    fabric.

  • ibsrpdm - List InfiniBand SCSI RDMA Protocol (SRP) targets on an IB fabric.

liraries

devid: device ID library. Refer to
here.

ibverbs: 使得用户空间进程能够使用 RDMA verbs(即进行 RDMA 操作)。Refer to
here.

dl: Dynamic Loader.