分布式存储_高性能RDMA网络_架构设计_性能调优参考_网卡排查命令_笔记

2023-11-03 22:15:31 浏览数 (2)

代码语言:javascript复制
qp属性: https://blog.csdn.net/weixin_42319496/article/details/119371088?spm=1001.2014.3001.5506
在开发过程中,将attr.retry_cnt和attr.rnr_retry设置为0是一个好习惯。如果代码中存在竞争,最好在开发阶段检测它们
attr.timeout中的值0表示一直等待ACK或NACK。这意味着,如果消息中的任何数据包丢失并且没有发送ACK或NACK,则不会发生任何重试,并且QP只会停止发送数据
attr.rnr_retry中的值7表示在远程端发送RNR Nack时,发送消息重试次数无上限

阿里建成全球超大规模数据中心内“RDMA高速网”:https://mp.weixin.qq.com/s/opJYVpcp1L9nP44uUMJoNw
从阿里云eRDMA看如何解决RDMA在数据中心大规模使用问题:https://mp.weixin.qq.com/s/JoTCFe0dbm4j72y_n3caTg
百度大规模 AI 高性能网络的设计与实践:https://mp.weixin.qq.com/s/o0vAQvAo6GnYxzzAkGtQWQ
AI大模型时代的RDMA网络杂谈:https://zhuanlan.zhihu.com/p/618357812
工业级大规模RDMA技术杂谈:https://zhuanlan.zhihu.com/p/510323418


关于 RDMA 与发送/接收以及互连和应用程序语义之间差异的讨论: https://translate.google.com/?sl=en&tl=zh-CN&text=A discussion on RDMA versus Send/Receive and the difference  between interconnect and application semantics &op=translate
关于 READ 与 WRITE 性能的论文,该论文可追溯到2006 年,它可能运行第一代 Infiniband NIC,以 SDR 速度 (10Gbps) 或最佳情况 DDR (20 Gbps)。当时 MPI 库正在尝试解决一些问题。幸运的是,情况已不再是这样,我们不再看到 READ 和 WRITE 之间的性能差异
https://github.com/NVIDIA/nccl/issues/609


rdma与socket对比: 

rdma: 跳过tcp/ip栈, ib(专用硬件) network或以太网都可用, 软件只管buffer, 不管pkg(交给HCA硬件), 接收端提前在接收队列准备好工作请求, 成功后放入完成队列, 然后从完成队列里面去poll事件来判断是否成功


注册内存:
调用ibv_get_device_list()得到RDMA硬件列表
挑选一个可用的RDMA硬件,比如mlx5, 调用ibv_open_device() 打开这个设备,返回一个设备上下文CTX1
在设备上下文CTX1的基础上去分配一个pd, 通过调用ibv_alloc_pd(),返回一个PD, 设为PD1
在设备上下文CTX1和PD1的基础上去注册内存,通过调用ibv_reg_mr()
1 ibv_get_device_list() 
2 ibv_open_device()  if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
3 ibv_alloc_pd()
4 ibv_reg_mr()

命令码: IB_USER_VERBS_CMD_REG_MR(==9)
struct ib_mr *mlx5_ib_reg_user_mr 底层驱动

ibv_reg_mr, 内部队列会锁住(pin)内存, 
The internal Queues (which require space: such as QP, CQ, SRQ) are using pinned memory.



[SPDK/NVMe存储技术分析]015 - 理解内存注册(Memory Registration) https://www.cnblogs.com/vlhn/p/8301427.html
vbers ibv_reg_mr|RDMA https://blog.csdn.net/bandaoyu/article/details/119460557
内存注册:
1. 虚拟地址 -> 物理地址, dma只认物理地址
2. 申请buffer, pin防止swapping out 置换内存
3. 授权访问

4.1 PINNED RDMA的问题, https://zhuanlan.zhihu.com/p/567720023
1,注册MR时PIN住物理内存这使得可注册的内存空间受限于物理内存大小。2,应用程序必须有锁住内存的权限。3,持续的在软硬件之间同步地址翻译表是一个很耗时的操作。这是因为malloc/mmap/stack都会导致页表变化。4,注册本身需要在HCA建立地址映射表,而get_user_pages以及填写页表都是耗时操作,这导致注册MR很慢
按需寻呼ODP, Memory Protection Tables(MPT) 内存保护表, Dynamic Random-Access DDR, 动态随机访问, shared virtual address (SVA) 共享虚拟地址, 

门铃机制:
在verbs编程中,doorbell 是随着context的创建而分配的,context内再创建QP/CQ时都会在这个doorbell page内分配具体的doorbell并关联至这个QP。当一个context关联的QP太多时可以再分配一个doorbell page。一个context支持多个doorbell可以有效地支持多个线程使用不同的QP并敲不同的doorbell,以避免并发性问题

大步发送, stride send, 
有的时候我们需要做矩阵转置,把行转为列,或者把列转为行。对应到DMA,就是把一段有规律的非连续数据发送到对端再放在一段连续的内存空间内,这跟scatter gather list有点像,区别在于SGL一般只用于描述少于16块的非连续数据,这些SGL可以是任意的内存区。而stride send所需发送的非连续内存块要多很多(多至K级别),它们有一定的规律:一般用base address, block size, stride size, repeat count四个参数描述

流式RDMA, Streaming RDMA, 

紧急协议, 发送端发一个小消息给接收端时直接将数据放在报文里带过去,这称之为eager protocol, 但若是一个大消息则可能因为接收侧没有这么大的接收缓冲区而失败,所以另一种做法是先发送一个小的控制消息rndv给接收侧告诉它真正消息的地址和长度以及key,接收侧会在接收缓冲区ready后反向来读数据。 Rendezvous protocol可以用软件实现也可以由硬件实现,但硬件实现可以让Rendezvous send变成类似read/write的单边操作,节省CPU资源

SRQ Limit Reached, 共享接收队列,工作请求元素WQE不够了, 

Extended Reliable Connected Transport Service (XRC), 

驱动配置: options mlx4_core log_num_mtt=24

可动态注册内存

客户端读一块数据流程:
1.客户端发起read request
2.服务端poll cq
3.服务端给客户端发ack
4.服务端给客户端write data
5.客户端发ack
6.服务端poll cq
7.服务端 post sr
8.客户端poll cq
9.客户端完成读取

wr opcode: rdma操作码
IBV_WR_SEND 发送
IBV_WR_RDMA_WRITE rdma写, No Receive Request will be consumed in the remote QP, 不消耗收端接收请求RQ, 收端也无感知, 发送端触发WC_WRITE, 接收端触发WC_RECV_RDMA_WITH_IMM
IBV_WR_RDMA_READ rdma读






ofed:
ofed 自带的工具,比如ib_bw之类的
查看ofed版本: ofed_info -s

port:
查看端口状态:
cat /sys/class/infiniband/mlx4_0/ports/ 1/state 2: INIT
cat /sys/class/infiniband/mlx4_0/ports/ 2/state 4: ACTIVE

查看传输层类型:
cat /sys/class/infiniband/mlx4_0/ports/ 1/link_layer InfiniBand
cat /sys/class/infiniband/mlx4_0/ports/ 2/link_layer Ethernet

查看固件版本:
cat /sys/class/infiniband/mlx4_0/fw_ver

Open Fabrics Enterprise Distribution(ofed): 开放企业发行版

wr: 用户层
wqe: 驱动层

用户空间API由用户空间库“libibverbs”提供。尽管一些RDMA
用户级的功能比内核级的功能要小,这就足够享受InfiniBand的好处了
技术

ucx项目编译
cd ~/
git clone git@github.com:openucx/ucx.git
cd ucx
./autogen.sh
./configure --prefix=/usr/local/ucx
make
sudo make install

brpc编译:
cd ~/
git clone git@github.com:opencurve/incubator-brpc.git | https://github.com/opencurve/incubator-brpc.git
cd incubator-brpc
git checkout ucx_am
mkdir bu
cd bu
cmake ..
make
cd ../example/multi_threaded_echo_c  
mkdir bu
cd bu
cmake ..
make
cp ../*.pem .


ibv_devices
rdma link
rdma dev
ibv_devinfo | grep state
ucx_info -d  
查看所有可用设备



扩展可靠连接
XRC(Extended Reliable Connection)

QP Context(简称QPC)

HCA(RNIC): 主机通道适配器/rdma网络接口控制器, rdma网卡

MMU(Memory Management Unit)


进程初始化的时候,页表的基地址(ph)会被储存在特殊的寄存器中
Memory mapping Input/Output

产生了IOMMU(x86平台)/SMMU(ARM平台)这种专门用于给外设进行地址翻译的设备。有了IOMMU/SMMU之后,外设跟使用MMU的CPU一样,看到的是一整片连续的虚拟地址。区别于CPU的VA,我们称这些地址为IO虚拟地址,即IOVA(Input/Output Virtual Address)

IOMMU/SMMU记录着地址的转换关系,外设发出的IOVA,会被它翻译为PA
DMA地址
外设(PCIe EP)通过DMA访问内存时,发出的地址就是DMA地址。结合上面的描述我们可以知道,当设备使用了IOMMU/SMMU时,DMA地址是IO虚拟地址IOVA。当未使用IOMMU/SMMU时,DMA地址是物理地址PA
https://www.zhihu.com/column/c_1231181516811390976

CM在作为协议时的全称为Communication Management Protocol,即通信管理协议。它指的是一种建立于Infiniband/RoCE协议基础之上的建链方式

大多数RoCE网卡都可以支持Socket和CM两种建链方式


app
libibverbs.so rdma-core
libmlx5.so  Mellanox ConnectX-5网卡的用户态驱动,也是个动态链接库,实现厂商的驱动逻辑
ib_uverbs.ko  ib_uverbs模块来解析命令, 负责通过ABI来处理用户态的系统调用请求,用户态verbs陷入内核
ib_core.ko
mlx5_ib.ko Mellanox ConnectX-5网卡的内核态驱动模块,负责直接和硬件交互
hw

编译rdma-core: https://runsisi.com/2021/03/07/rdma-core/

用户态和内核态交互: 慢路径和快路径
https://zhuanlan.zhihu.com/p/346708569




ibv_post_send()这个接口也讲过几次了,功能就是用户下发WR给硬件。假设用户下发了一个SEND的WQE,这一过程具体完成了哪些工作呢:从QP Buffer中获得下一个WQE的内存首地址(ibv_create_qp()中申请的)根据与硬件约定好的结构,解析WR中的内容填写到WQE中数据区域通过sge指定,sge指向的内存位于MR中(ibv_reg_mr()中注册的)填写完毕,敲Doorbell告知硬件(地址是ibv_open_device()中映射得到的)硬件从QP Buffer中取出WQE并解析其内容硬件通过映射表(ibv_reg_mr()中建立的),将存放数据的虚拟地址转换成物理地址,取出数据硬件组包、发送数据


使用Soft-RoCE的目的是为了学习协议而不是实现原理
Soft RoCE 是一种软件实现,它允许 RoCE 在任何以太网网络适配器上运行,无论它是否提供硬件加速。 它利用与 RoCE 相同的效率特性,在任何 NIC 上提供完整的 RDMA 堆栈实施, Soft RoCE 驱动程序通过 Linux 网络堆栈实现 InfiniBand RDMA 传输。 它使具有标准以太网适配器的系统能够与硬件 RoCE 适配器或与另一个运行 Soft-RoCE 的系统进行互操作
配置: https://enterprise-support.nvidia.com/s/article/howto-configure-soft-roce

Infiniband和RXE(即Soft-RoCE功能的软件实体)的相关选项
ibverbs各厂商用户态驱动(包括RXE)rdma x ethernet


DDP 零拷贝

ULP
Upper Layer Protocol,上层协议

LLP
Lower Layer Protocol,下层协议


Node/Peer是两个不同层级的概念,Node是物理实体,Peer是协议实体。一个Node上可以有多个Peer
Data Sink: 收集方


ibv_create_qp() and rdma_create_qp() are almost the same thing. ibv_create_qp() returns a pointer to the created queue pair, rdma_create_qp() assigns the created queue pair to id->qp.

There are the Infiniband Verbs, IBV, and the RDMA verbs. RDMA verbs have equivalents for many of the Infiniband Verbs. With Infiniband verbs, you have a bunch of individual pointers to maintain, the queue pair pointer, pointers to the completion queues, pointer to the protection domain, etc. With the RDMA verbs, these are all collected under the id structure. Look at /usr/include/rdma/rdma_cma.h, struct rdma_cm_id {}.

You can still use ibv_create_qp() in an RDMA verbs environment, but you need to make sure that you populate the RDMA id->qp with the returned queue pair, if you want to do any further operations with the RDMA verbs or RDMA Connection Manager.

rdma_create_ep, RDMA Create End Point, collapses a handful of RDMA calls, into one call. These include rdma_create_id(), rdma_create_qp(), rdma_resolve_addr(), and rdma_resolve_route().


1、调用ibv_get_device_list()函数,它返回NULL,意味着什么?

答:这是一个基础的verb,一般不会失败,可以检查一下 ib_uverbs 模块是否被加载

 

2、调用ibv_get_device_list()函数,返回空的list,意味着什么?

答:驱动没有找到任何的RDMA设备

如果你的机器存在RDMA设备,可以用lspci检查
使用 lsmod 检查支持RDMA设备的底层驱动模块是否加载
使用 dmesg /var/log/message 检查是否有报错


ibv_query_device
ibv_devinfo -v

list of verbs devices found for FI_EP_MSG


RD和UC类型,以及XRC(Extended Reliable Connection)扩展可信连接,SRD(Scalable Reliable Datagram)等更复杂的服务类型



RDMA用完成事件通道读取CQE的方式如下:

用户程序通过调用ibv_create_comp_channel创建完成事件通道;
接着在调用ibv_create_cq创建CQ时关联该完成事件通道;
再通过调用 ibv_req_notify_cq 来告诉CQ当有新的CQE产生时从完成事件通道来通知用户程序;
然后通过调用 ibv_get_cq_event 查询该完成事件通道,没有新的CQE时阻塞,有新的CQE时返回;
接下来用户程序从 ibv_get_cq_event 返回之后,还要再调用ibv_poll_cq从CQ里读取新的CQE,此时调用ibv_poll_cq一次就好,不需要轮询。必须定期轮询 CQ 以防止溢出。 如果发生溢出,CQ 将被关闭并发送一个异步事件 IBV_EVENT_CQ_ERR


yum install libibverbs  libibverbs-devel libibverbs-utils librdmacm librdmacm-devel librdmacm-utils perl-Switch elfutils-libelf-devel  -y

libibverbs 是一个库,它允许用户空间进程使用 RDMA “动词”,如 InfiniBand 架构规范和 RDMA 协议动词规范中所述。这包括从用户空间直接硬件访问 InfiniBand/iWARP 适配器(内核旁路)以进行快速路径操作。包含特定于设备的插件 ibverbs 用户空间驱动程序 - libbxnt_re - libcxgb3 - libcxgb4 - libhfi1 - libhns - libi40iw - libipathverbs - libmlx4 - libmlx5 - libmthca - libnes - libocrdma - libqedr - librxe - libvmw_pvrdma libibverbs 是一个库,允许用户空间进程使用 InfiniBand 架构规范和 RDMA 协议动词规范中描述的 RDMA “动词”。这包括从用户空间直接硬件访问 InfiniBand/iWARP 适配器(内核旁路)以进行快速路径操作。包含特定于设备的插件 ibverbs 用户空间驱动程序 - libbxnt_re - libcxgb3 - libcxgb4 - libhfi1 - libhns - libi40iw - libipathverbs - libmlx4 - libmlx5 - libmthca - libnes - libocrdma - libqedr - librxe - libvmw_pvrdma

显示默认 RoCE 模式
cat /sys/kernel/config/rdma_cm/mlx5_0/ports/1/default_roce_mode
cat /sys/devices/{pci-bus-address}/roce_enable
启用/禁用 roce: echo <0|1> > /sys/devices/{pci-bus-address}/roce_enable

所有 mlx5 设备均启用 RoCE。 启用 RoCE 后,设备会将所有流向 UDP 端口 4791 的流量视为 RoCE 流量

ibstat rxe0
rdma link add rxe0 type rxe netdev enp2s0
lsmod | grep ib
ip link show enp2s0 #物理状态
cat /etc/rdma/modules/rdma.conf
ibping -S -C mlx4_1 -P 1
ibping -c 50 -C mlx4_0 -P 1 -L 2
qperf -v -i mlx4_0:1 192.0.2.1 rc_bi_bw
RDMA 代码由内核和用户空间代码组合而成

yum groupinfo "Infiniband Support"
yum -y groupinstall "Infiniband Support"
systemctl start rdma.service
systemctl start opensm.service 子网服务


ibv_post_send -> post_send -> mlx5_post_send

sfence 写串行化


ibv_post_send -> verbs.h -> post_send -> user_space_driver -> .post_send     = mlx5_post_send -> _mlx5_post_send -> post_send_db -> mmio_flush_writes() -> #define mmio_flush_writes() asm volatile("sfence" ::: "memory") -> 

man ibv_post_send

#include <infiniband/verbs.h>   // IB_VERBS 基础头文件
#include <rdma/rdma_cma.h>      // RDMA_CM CMA 头文件 用于CM建链
#include <rdma/rdma_verbs.h>    // RDMA_CM VERBS 头文件 用于使用基于CM的Verbs接口

ibv_post_send()
这个接口也讲过几次了,功能就是用户下发WR给硬件。假设用户下发了一个SEND的WQE,这一过程具体完成了哪些工作呢:

从QP Buffer中获得下一个WQE的内存首地址(ibv_create_qp()中申请的)
根据与硬件约定好的结构,解析WR中的内容填写到WQE中
数据区域通过sge指定,sge指向的内存位于MR中(ibv_reg_mr()中注册的)
填写完毕,敲Doorbell告知硬件(地址是ibv_open_device()中映射得到的)
硬件从QP Buffer中取出WQE并解析其内容
硬件通过映射表(ibv_reg_mr()中建立的),将存放数据的虚拟地址转换成物理地址,取出数据
硬件组包、发送数据

Doorbell其实分为两种,一种工作方式类似于中断,我们称为硬Doorbell,一般用于SQ。是ibv_open_device过程中,调用驱动注册的钩子,到内核态映射的一个PCI BAR空间的地址(可以认为是寄存器),所有QP共用一份。写入时会携带QPN,一旦写入硬件会立刻收到,并且知道是哪个QP下发了新的WQE;另一种方式我们称为软Doorbell,也叫做Record Doorbell,实际上是一个普通的内存地址,每个QP都是独立分配的。这个地址会被记录到QPC中,一般用于RQ。硬件有需求的时候才回去读这个地址,然后就知道RQ里面有多少WQE了

ibv_devinfo -d rxe0 -v

socket/cm, 

Component Pyramid of verbs: 金字塔


rdma_create_event_channel -> /dev/infiniband/rdma_cm -> LATEST_SYMVER_FUNC(ibv_alloc_pd



IBV_WC_WR_FLUSH_ERR
如果发送和接收缓冲区大小不匹配,那么发送或接收请求可能会产生无法恢复的队列对错误。 可以向通信过程中添加步骤来避免此问题。

如果接收缓冲区的大小与发送缓冲区的大小不匹配,那么可能会发生此问题。发送操作将失败,并且在接收方端操作码为 IBV_WC_LOC_LEN_ERR,在发送方端操作码为 IBV_WC_REM_INV_REQ_ERR。 此类错误导致队列对转至错误状态,并且进一步的发送或接收请求会产生操作码 IBV_WC_WR_FLUSH_ERR。 无法恢复队列对。

要避免此问题,请确保发布的接收缓冲区的长度足以存放发送请求。如果长度未知,那么可以对应用程序进行编程,以在发送之前传达所需长度。在另一端,可以为缓冲区准备用于接收的相应大小。
工作请求已刷新错误:当 QP 转换为错误状态时,工作请求正在处理中或未完成。
IB WC WR FLUSH ERR
我们在一些站点上看到了IB_WC_WR_FLUSH_ERR错误。这里记录了对该错误的一个解释。

https://www.ibm.com/support/knowledgecenter/SSYKE2_7.0.0/com.ibm.java.lnx.70.doc/diag/problem_determination/rdma_jverbs_qp_error.html

现将有关部分粘贴如下。

如果发送和接收缓冲区大小不匹配,发送或接收请求会导致队列对错误,无法恢复。您可以在通信过程中添加一些步骤来避免这个问题。

如果接收缓冲区的大小与发送缓冲区的大小不匹配,则会出现此问题。发送操作失败,接收端出现操作码IBV_WC_LOC_LEN_ERR,发送端出现操作码IBV_WC_REM_INV_REQ_ERR。这样的错误会导致队列对进入错误状态,进一步发送或接收请求会导致操作码IBV_WC_WR_FLUSH_ERR。这一对队列无法恢复。

为了避免这个问题,确保发布的接收缓冲区的长度足以容纳发送请求。如果不知道长度,可以在发送前对应用程序做出修改,以传达所需的长度。此外,还可以准备一个合适大小的缓冲区来接收。

在 Lustre 2.10 及以前的版本,我任务这是可能发生的,因为我们在创建QP时减少了max_send_wr,而没有管理队列深度。这可能会导致QP在创建时两端的缓冲区大小不同。


IBV_WC_RETRY_EXC_ERR

Connection Management Abstraction:连接管理抽象


协议错误:
传输层重试次数超过阈值,驱动报上来的, 超出传输重试计数器
在计算节点(节点间)之间通信时,如果发送/接收消息的大小超过 65535,则会出现以下错误
Transport retry count exceeded on mlx5_0:1/RoCE, 此错误表示网络层丢包过多,请尝试启用 RoCE 有损配置
can you pls try to enable RoCE Lossy configuration, as described in https://community.mellanox.com/s/article/How-to-Enable-Disable-Lossy-RoCE-Accelerations?
参考: ib_mlx5_log.c:143  Transport retry count exceeded on mlx5_0:1/RoCE (synd 0x15 vend 0x81 hw_synd 0/0)
[Users] Communication (Send/Recv) error according to message size(65535)
https://github.com/openucx/ucx/blob/master/src/uct/ib/mlx5/ib_mlx5_log.c
case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
	snprintf(err_info, sizeof(err_info), "Transport retry count exceeded");
	err_status = UCS_ERR_ENDPOINT_TIMEOUT;
	break;

错误码:12 IBV_WC_RETRY_EXC_ERR, enum ibv_wc_status rdma-core, [IBV_WC_RETRY_EXC_ERR]		= "transport retry counter exceeded"
const char *ibv_wc_status_str(enum ibv_wc_status status)

rdma定位命令, ofed命令dump
ucx_info -v
cat /etc/redhat-release
uname -a
ofed_info -s
ibstat
ibv_devinfo -v
ofed_info
ucx_info -d 显示 UCX 识别的传输和设备, 查看网络设备及支持的传输模式

irdma Linux*驱动程序使支持RDMA的英特尔网络设备具有RDMA功能 intel rdma

mlx5_poll_cq
	poll_cq
		mlx5_poll_one | mlx5_parse_lazy_cqe
			mlx5_parse_cqe
				mlx5_handle_error_cqe
					case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
						return IBV_WC_RETRY_EXC_ERR;


 Physical Page Number (PPN) 物理页数量
参考链接: 华为 https://support.huawei.com/enterprise/zh/doc/EDOC1100195164/c8f1cd7f
Mellanox网卡环境使用ud_x与shm组合传输模式,鲲鹏RoCE网卡环境使用ud和shm组合的传输模式,原因是ud模式下创建QP的数量远低于rc模式且通讯速率较快,鲲鹏RoCE网卡环境不支持ud_x模式

查看默认环境变量: ./bin/ucx_info -f|grep -v '#'



@afernandezody 基本上有 2 个选项来配置 RoCE 结构:
有损模式(可能在交换机和网卡中默认) - 推荐 - 在这种情况下,需要进行上述配置以避免丢包过多
无损模式 - 因此结构不会丢弃数据包。
在 https://community.mellanox.com/s/article/recommended-network-configuration-examples-for-roce-deployment 中查看更多详细信息。
不幸的是,如果不对系统配置进行某种更改,就不可能解决这个问题。
不需要 UCX_IB_TRAFFIC_CLASS 和 UCX_IB_GID_INDEX,因为它们是根据结构配置自动设置的。

H3C UIS超融合产品RDMA全无损网络配置指导-5W100: https://www.h3c.com/cn/Service/Document_Software/Document_Center/Home/H3Cloud/00-Public/Configure/Operation_Manual/H3C_UIS_RDMA-Long/?CHID=778602#

ibdev2netdev 是 MLNX_OFED 包中最有用的脚本之一,因为它将适配器端口映射到网络设备。

一些网络及其相关应用程序将受益于新的 Mellanox 有损 RoCE 功能。 这些特性包括:自适应重传、传输窗口和慢启动。 它们允许网络管理员在有损网络上提供 RoCE 支持。 这篇文章旨在演示如何启用/禁用这些功能。

adaptive retransmission 自适应重传
transmission window   传输窗口
and slow start 慢启动

查看mlx设备:
lspci | grep Mell

查看无损配置(要查看当前的有损 RoCE 加速状态:)
lspci|grep -i Mellanox
mlxreg -d 17:00.0 --reg_name ROCE_ACCL --get

开启有损加速:
mlxreg -d 84:00.1 --reg_name ROCE_ACCL --set "roce_adp_retrans_en=0x1,roce_tx_window_en=0x1,roce_slow_restart_en=0x1,roce_slow_restart_idle_en=0x1"

禁用:
mlxreg -d 84:00.1 --reg_name ROCE_ACCL --set "roce_adp_retrans_en=0x0,roce_tx_window_en=0x0,roce_slow_restart_en=0x0,roce_slow_restart_idle_en=0x0"

*_field_select 是否支持
*_en 是否启用

连接类型:
qp_type = IBV_QPT_RC

查看网接口
ls /sys/class/infiniband/*/device/net



SPDK NVMe-oF RDMA 传输是在 libibverbs 和 rdmacm 库之上实现的,这些库已打包并在大多数 Linux 发行版上可用。它不通过 DPDK 使用用户空间 RDMA 驱动程序堆栈。

为了扩展到大量连接,SPDK NVMe-oF RDMA 传输为每个轮询组分配一个 RDMA 完成队列。分配给轮询组的所有新 qpairs 都有自己的 RDMA 发送和接收队列,但共享这个公共完成队列。这允许轮询组轮询单个队列以获取传入消息,而不是遍历每个队列。

每个 RDMA 请求都由一个状态机处理,该状态机将请求遍历多个状态。这使代码保持井井有条,并使所有极端情况更加明显。

RDMA SEND、READ 和 WRITE 操作相对于彼此进行排序,但 RDMA RECV 不一定与 SEND 确认一起排序。例如,可以在检测到对包含 NVMe 完成的先前 SEND 的确认之前检测到包含新 NVMe-oF 胶囊的传入 RDMA RECV 消息。这在全队列深度是有问题的,因为可能还没有空闲的请求结构。为了处理这个问题,RDMA 请求结构被分成两部分——一个 rdma_recv 和一个 rdma_request。新的 RDMA RECV 将始终获取空闲的 rdma_recv,但可能需要在队列中等待 SEND 确认,然后才能获取完整的 rdma_request 对象。

此外,RDMA NIC 为 READ/WRITE 操作公开与 SEND/RECV 操作不同的队列深度。 RDMA 传输根据 SEND/RECV 操作限制报告可用队列深度,并将根据需要在软件中排队以适应 READ/WRITE 操作的(通常较低)限制。



内核树:
tree /lib/modules/*/kernel/drivers/infiniband/

# 查看邮件
apk add lshw
lshw -class network

# 查看 pci 设备
apk add pciutils
lspci | grep -i 'ethernet'


# 常见厂商信息
dmesg | egrep -i "Mellanox|InfiniBand|QLogic|Voltaire"
# ib 状态, 需要安装扩展包 show how many ports
ibstat
# 查看设备
ls /sys/class/infiniband/
# 查看物理状态
grep . /sys/class/infiniband/*/ports/*/phys_state
# 查看设备状态
grep . /sys/class/infiniband/*/ports/*/state
# 查看 mtu 和 地址
grep . /sys/class/net/*/{mtu,address}

# 查看设置
ethtool eth2


# 确保默认路由是 ib 卡
ip ro get 8.8.8.8

# 如果不是, 则替换默认路由
# 假设 eth2 为 ib 卡
ip route replace default via 192.168.1.1 dev eth2

测试:
#bandwidth
echo "ib_send_bw"
ib_send_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 > /dev/NULL &
sleep 3
ib_send_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 192d.168.1.2
sleep 3
echo "ib_read_bw"
ib_read_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send > /dev/NULL &
sleep 3
ib_read_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send 192.168.1.2
sleep 3
echo "ib_write_bw"
ib_write_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send > /dev/NULL &
sleep 3
ib_write_bw -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send 192.168.1.2
sleep 3
#lat
echo "ib_send_lat"
ib_send_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 > /dev/NULL &
sleep 3
ib_send_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 192.168.1.2
sleep 3
echo "ib_write_lat"
ib_write_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 > /dev/NULL &
sleep 3
ib_write_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send -I 96 192.168.1.2
sleep 3
echo "ib_read_lat"
ib_read_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send > /dev/NULL &
sleep 3
ib_read_lat -n 10000 -d irdma1 -i 1 -F --report_gbits --use_old_post_send 192.168.1.2
sleep 3
#ibv_xx_pingpong
echo "ibv_rc_pingpong"
ibv_rc_pingpong -d irdma1 -g 1 > /dev/null &
sleep 3
ibv_rc_pingpong -d irdma1 -g 1 192.168.1.2
sleep 3
echo "ibv_ud_pingpong"
ibv_ud_pingpong -d irdma1 -g 1 > /dev/null &
sleep 3
ibv_ud_pingpong -d irdma1 -g 1 192.168.1.2
sleep 3
echo "rping"
#rping
rping -s -a 192.168.1.2 -v -d -C 3 > /dev/NULL &
sleep 3
rping -c -a 192.168.1.2 -v -d -C 3
-----------------------------------

查看状态:
rdma-statistic

RoCE/RDMA Tools

查看软件rdma支持情况
cat /boot/config-$(uname -r) | grep RXE


channel->fd = open("/dev/infiniband/rdma_cm", O_RDWR | O_CLOEXEC); //可以看出rdma_event_channel本质上就是一个fd
对于rdma编程,目前主流实现是利用rdma_cm来建立连接,然后利用verbs来传输数据。
rdma_cm和ibverbs分别会创建一个fd,这两个fd的分工不同。rdma_cm fd主要用于通知建连相关的事件,verbs fd则主要通知有新的cqe发生。当直接对rdma_cm fd进行poll/epoll监听时,此时只能监听到POLLIN事件,这意味着有rdma_cm事件发生。当直接对verbs fd进行poll/epoll监听时,同样只能监听到POLLIN事件,这意味着有新的cqe



/etc/libibverbs.d

local_key
在RDMA硬件中实现虚实地址转换的过程是这样的,首先用l_key指向一个mpt表,这个表是一个访问权限表,里面还有物理地址表的index,指向了一串物理地址


dma: 

r-key 发给对端


na_ofi_cq_read


read and write
通过send和receive交换addr和rkey, 收到后,各自存到连接上,后续使用
WRITE/READ操作中的目的地址和钥匙是如何获取的呢?通常可以通过我们刚刚讲过的SEND-RECV操作来完成,因为拿到钥匙这个过程总归是要由远端内存的控制者——CPU允许的

文件传输

 /sbin/ifconfig ib0 | grep "inet addr"

在查看使用 ibverbs 编程的细节之前,我们应该介绍一些先决条件。 我强烈建议通读 InfiniBand Trade Association 的介绍——尤其是第一章和第四章(只有十三页!)。 我还假设您熟悉 C 语言编程,并且至少对套接字、MPI 和一般网络有一定的了解。

查看工作模式:
/sbin/connectx_port_config -s

查看网卡状态:
hca_self_test.ofed
ibstat ibstatus ibv_devinfo ibv_devices #查看本主机的infiniband设备 ibnodes #查看网络中的infiniband设备
Ethernet 的工作模式

ibstatus 查看网卡状态, 工作模式, 协议

查看模块:
openib-diags 开源IB诊断工具
/etc/init.d/openibd status

service openibd start

忽略内核差异, vim /etc/init.d/openibd FORCE=0 -> FORCE=1 

打开设备:
ibv_devinfo -d mlx4_0


vrb_ep_close
	vrb_flush_sq 造了一个工作完成
		vrb_wr2wc_opcode

事件
reboot -f : 无事件
kill engine: DISCONNECTED


rdma网卡
systemctl status openibd
/etc/init.d/openibd status
https://docs.oracle.com/cd/E19244-01/820-7293-10/rfem3_software.html
自动加载模块列表: /etc/infiniband/openib.conf

探测节点:
ibnetdiscover

内核还包括套接字直接协议 (SDP) 驱动程序、IP over Infiniband (IPoIB) 和 SCSI RDMA 协议 (SRP) 驱动程序。


HCA每消费掉一个WQE, 都会生成一个CQE。因此,在系统A的完成队列中放置一个CQE,意味着对应的WQE的发送操作已经完成。同理,在系统B的完成队列中也会放置一个CQE,表明对应的WQE的接收操作已经完成。如果发生错误,HCA依然会创建一个CQE。在CQE中,包含了一个用来记录传输状态的字段


用户态驱动可以发现设备, 为什么需要内核态驱动: 
[SPDK/NVMe存储技术分析]012 - 用户态ibv_post_send()源码分析
https://www.cnblogs.com/vlhn/p/7997457.html
无论是/sys/class/infiniband_verbs还是/sys/class/infiniband路径,都跟sysfs紧密相关。那么,谁有能力在/sys/class/infiniband下面创建设备信息?答案自然是RDMA卡的内核驱动,比如mlx5_ib.ko。因此,我们可以看到,libmlx5和libibverbs紧密配合发现mlx5设备,但是没有直接使用PCIe,而是借助于内核驱动mlx5_ib.ko在加载时创建的sysfs信息。到此为止,我们可以得到如下证据确凿的结论:
用户态驱libmlx5没有通过PCIe发现mlx5设备的能力,因为基于sysfs信息去发现mlx5设备,所以mlx5的Linux内核驱动是必须的。而mlx5的内核驱动,自然是通过PCIe去sysfs那里注册对应的mlx5设备的



rdma指令记录
查看映射关系
mlnx_qos -i eth2   (mellonx)

设置用L3做流控
mlnx_qos -i eth2 --trust=dscp  (mellonx)

修改dscp到priority 映射
dscp 30 映射到修改dscp到priority 6
# mlnx_qos -i eth2 --dscp2prio set,30,6    (mellonx)

使能PFC
# mlnx_qos -i <interface> --pfc 0,0,0,1,0,0,0,0   

修改tc和prio的映射(默认除了tc0对应prio1,tc对应prio0,其他的都是对应的,如tc2-prio2,tc3-prio3,tc4-prio4……)
mlnx_qos -i ib3b-0 -p 0,1,2,3,4,5,6,7

端口各优先级的收发计数
#测量该接口发送和接收的 Xon 和 Xoff(传输开启和关闭)帧的数量:
# watch -n 1 "ethtool -S eth1 | grep prio"

流控:
https://www.ruijie.com.cn/jszl/82183/


(intel
 请注意,Rx 计数器全为 0。当适配器通过交换机连接时,rx_priority_* 计数器可能为 0,表明适配器尚未从交换机收到任何暂停帧。根据网络中的压力水平,如果交换机有足够的缓冲来跟上主机需求,这是可以接受的。但是,对于高压力流量(例如更大规模的 HPC 应用程序),交换机通常会向主机发送暂停帧。通常,预计会同时看到 tx 和 rx_priority 计数器。
请注意,某些 Tx 计数器具有相同的值。在 800 系列 QoS 实施中,如果为traffic class中的任何priority启用 PFC,则该traffic class中的所有priority都会获得暂停帧。这意味着同一 TC 中所有priority的计数器都会一致递增,而不管导致 PFC 触发的特定单个priority如何。如果所有priority都映射到同一个 TC,它们都会一致增加。)

查看GID
show_gids          (mellonx;intel自己也写同样的脚本,脚本内容见末尾)
show_gids mlx5_5   (mellonx)查看设备可用端口, gid_index, rmda版本

查看端口丢弃
show_drop        (mellonx;intel自己也写同样的脚本,脚本内容见末尾)

弃包统计
ethtool -S enp175s0f0 | grep drop

watch -n 1 "ethtool -S enp175s0f0 | grep drop"   #1 s 刷新一次

各个优先级收发包统计

watch -n 1 "ethtool -S ib3b-0 | grep prio"


查看device
ibdev2netdev     (mellonx;intel自己也写同样的脚本,脚本内容见末尾)

ibdev2netdev –v  (mellonx)


验证 InfiniBand 链接是否已启动

hca_self_test.ofed   (mellonx)


Mellanox OFED 安装的信息

/etc/infiniband/info

看自动加载的模块列表
/etc/infiniband/openib.conf


检查Mellanox网卡是否安装和版本
[root@rdma61 ~]#  lspci | grep Mellanox


查看系统里所有的网卡和工作状态:
[root@rdma63 tcpdump]# ip a

[root@rdma63 tcpdump]# ibv_devices
    device                 node GUID
    ------              ----------------
    mlx5_1              98039b03009a4296
    mlx5_0              98039b03009a2b3a

[root@rdma63 tcpdump]# ibv_devinfo 

或

[root@rdma63 tcpdump]# ibv_devinfo mlx5_0

重新启动RDMA驱动

/etc/init.d/openibd restart

如果驱动不正常,虽然service network restart 可以启动Ethernet端口,但实际rdma驱动并未成功加载。
执行/etc/init.d/openibd restart 可以看到很多的错误。(还有记得把ibacm启动, service ibacm start)

The ibacm service is responsible for resolving names and addresses to InfiniBand path information and caching such data. 
It should execute with administrative privileges. 
The ibacm implements a client interface over TCP sockets, which is abstracted by the librdmacm library.


mellonx信息搜集

/usr/sbin/sysinfo-snapshot.py

//****************************************************交换机****************************************

S6820《H3C S6820 系列以太网交换机 二层技术-以太网交换配置指导》P11:PFC 优先级高于FC,设置了PFC 则忽略FC

2.配置H3C交换机

a)    配置优先级信任模式为DSCP:

例如:
[H3C]sys
[H3C]interface HundredGigE1/0/6
[H3C-HundredGigE1/0/6] 6

*配置信任模式为DSCP,交换机才会使用 报文自带的DSCP做映射。
设置信任模式为DSCP,则进入交换机的报文优先级映射会涉及到3个表:
进-->出 映射,
dscp-dot1p    #入端口报文为dscp会被交换机映射到lp队列
dscp-dp       #入端口报文为dscp会被交换机映射到dp队列
dscp-dscp     #入端口报文的dscp会被交换机改为dscp转发
(优先级可分为两类:报文携带优先级和设备调度优先级。
设备调度优先级是指报文在设备内转发时所使用的优先级,只对当前设备自身有效。
设备调度优先 级包括以下几种: 
• 本地优先级(LP):设备为报文分配的一种具有本地意义的优先级,每个本地优先级对应一 个队列,本地优先级值越大的报文,进入的队列优先级越高,从而能够获得优先的调度。
• 丢弃优先级(DP):在进行报文丢弃时参考的参数,丢弃优先级值越大的报文越被优先丢弃。)

display qos map-table dscp-dot1p

b)    配置PFC功能的开启模式
例如:
[H3C]sys
[H3C]interface HundredGigE1/0/6
[H3C-HundredGigE1/0/6] priority-flow-control enable


6.显示接口的PFC信息
display priority-flow-control interface 显示全部
display priority-flow-control interface [ interface-type [ interface-number ] ] 显示某个

关闭PFC:undo priority-flow-control


7,使能PFC后还需指定PFC作用的不弃包的等级priority-flow-control no-drop dot1p dot1p-list
如:
priority-flow-control no-drop dot1p 0
priority-flow-control no-drop dot1p 0,1,3

(dot1p和dscp的映射见display qos map-table  dscp-dot1p )
http://www.h3c.com/cn/d_201906/1206016_30005_0.htm

显示端口是否开启FC:----不是PFC,设置了PFC就忽略FC
display interface [接口]
如: display interface  HundredGigE1/0/2
缩写:dis int HundredGigE1/0/4

(1、端口入方向报文计数错误字段解释 
input errors:各种输入错误的总数。 
runts:表示接收到的超小帧个数。超小帧即接收到的报文小于 64 字节,且包括有效的 CRC 字段,报文格式正确。 
giants:是超过端口设置的 Maximum Frame Length 的报文个数。 CRC:表示接收到的 CRC 校验错误报文个数。 
frame:端口接收时出错的报文。 

2、端口出方向报文计数错误字段解释
 output errors:各种输出错误的总数。 
 aborts:表示发送失败的报文总数。 
 deferred:表示延迟报文的总数。报文延迟是指因延迟过长的周期而导致发送失败的报文,而这些报文由于发送媒质繁忙而等待了超过 2 倍的最大报文发送时间。 
 collisions:表示冲突帧总数,即在发送过程中发生冲突的报文。 l
 ate collisions:表示延迟冲突帧,即发送过程中发生延迟冲突超过 512bit 时间的帧。
 )


H3C 二层命令参考:http://www.h3c.com/cn/d_202104/1397802_30005_0.htm


****************************
显示和维护(H3C交换机)
****************************
1.显示指定优先级映射表配置情况 
display qos map-table  dot1p-dp | dot1p-exp | dot1p-lp | dscp-dot1p | dscp-dp | dscp-dscp | exp-dot1p | exp-dp ] 
如:display qos map-table dscp-dscp

2.    显示接口优先级信任模式信息(sys视图)
 display qos trust interface [ interface-type interface-number ]
如:
display qos trust interface HundredGigE1/0/1

3.    显示端口简单信息
display interface brief
4.    显示端口在该间隔时间内统计的报文信息
display interface
5.    显示Qos trust设置
display qos trust int
6.    显示接口的PFC信息
display priority-flow-control interface 显示全部
display priority-flow-control interface [ interface-type [ interface-number ] ] 显示某个

显示收发和暂停统计

-显示全部端口
-display interface
-显示某个端口
-display interface HundredGigE1/0/2

查看拥塞drop包(弃包/丢包)
display packet-drop 
display packet-drop interface HundredGigE1/0/4
《接口管理命令参考》http://www.h3c.com/cn/d_201906/1206016_30005_0.htm
//===============================================================================测试================================================================


Tos=============
--tos=<tos value>  Set <tos_value> to RDMA-CM QPs. available only with -R flag. values 0-256 (default off)

ibdump -d mlx5_0 -i 1  -w        sniffer.acp     #抓包
ib_send_bw -d mlx5_0     --rdma_cm               #服务端
ib_send_bw 192.169.31.54 --rdma_cm  --tos=12 –R  #客户端1100



show_gid
==========================
Intel show_drop 
==========================
#!/bin/bash
function show_drop()
{
        for device in `ls /sys/class/infiniband/`
        {
          echo ""
          echo -e  "e[1;32m${device}e[0m" 
          cd  /sys/class/infiniband/${device}/hw_counters
         
          for f in *Discards
          {
             echo -n "$f: "
             cat "$f"
          }
        }
}
 
show_drop

*intel官方提供的脚本:
# cd /sys/class/infiniband/irdma-enp175s0f0/hw_counters  
# for f in *Discards; do echo -n "$f: "; cat "$f"; done  


==========================
Inetl ibdev2netdev
==========================
#!/bin/bash
echo "--------------------------------------"
echo "script locate:/usr/bin/ibvdev2netdev"
echo "Author:liangchaoxi"
echo "***************************************"
ibv_devices|awk '{system("echo "$1""-->"`ls /sys/class/infiniband/"$1"/device/net`")}' |& grep -Ev '/device/net|device|-------->'
echo "***************************************"
ip route
echo "--------------------------------------"

Mellonx

显示GID
show_gids

显示OFED显示
ofed_info

显示网卡、驱动版本等信息
hca_self_test.ofed

自测
[root@rdma61 ~]# hca_self_test.ofed
---- Performing Adapter Device Self Test ----
Number of CAs Detected ................. 2
PCI Device Check ....................... PASS
Kernel Arch ............................ x86_64
Host Driver Version .................... OFED-internal-4.5-1.0.1: 4.14.0-49.12.x86_64
Host Driver RPM Check .................. PASS
Firmware on CA #0 NIC .................. v16.24.1000
Firmware on CA #1 NIC .................. v16.23.1020
Host Driver Initialization ............. PASS
Number of CA Ports Active .............. 2
Port State of Port #1 on CA #0 (NIC)..... UP 4X QDR (Ethernet)
Port State of Port #1 on CA #1 (NIC)..... UP 4X QDR (Ethernet)
Error Counter Check on CA #0 (NIC)...... PASS
Error Counter Check on CA #1 (NIC)...... PASS
Kernel Syslog Check .................... FAIL
    REASON: Kernel syslog reported: Driver messages 
      [681196.776180] java invoked oom-killer: gfp_mask=0x14201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), nodemask=(null),  order=0, oom_score_adj=0
      [681443.262537] devmgrdaemon invoked oom-killer: gfp_mask=0x14000c0(GFP_KERNEL), nodemask=(null),  order=0, oom_score_adj=0
      [684264.725346] objecter_timer invoked oom-killer: gfp_mask=0x14201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), nodemask=(null),  order=0, oom_score_adj=0
      [782281.333718] themis invoked oom-killer: gfp_mask=0x14201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), nodemask=(null),  order=0, oom_score_adj=0
      [782285.206503] devmgrdaemon invoked oom-killer: gfp_mask=0x14201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), nodemask=(null),  order=0, oom_score_adj=0
Node GUID on CA #0 (NIC) ............... 98:03:9b:03:00:9a:31:ba
Node GUID on CA #1 (NIC) ............... 98:03:9b:03:00:9a:4c:1a
------------------ DONE ---------------------


检查Mellanox网卡是否安装和版本
[root@rdma61 ~]#  lspci | grep Mellanox
0000:18:00.0 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5]
0000:3b:00.0 Ethernet controller: Mellanox Technologies MT27800 Family [ConnectX-5]

命令查看网口映射关系。

#ibdev2netdev 

[root@rdma64 ibdump-master]# ibdev2netdev
mlx5_0 port 1 ==> eth18-0 (Up)
mlx5_1 port 1 ==> ib3b-0 (Up)

ibv_devices  列出device

[root@rdma63 tcpdump]# ibv_devices
    device                 node GUID
    ------              ----------------
    mlx5_1              98039b03009a4296
    mlx5_0              98039b03009a2b3a


打印出device信息
[root@rdma63 tcpdump]# ibv_devinfo 

或

[root@rdma63 tcpdump]# ibv_devinfo mlx5_0


ibstatus 更换网卡工作模式


有些网卡,当你安装好驱动后,通过 ibstatus 命令,会出现下面的情况:

可以看到,该网卡现在处于 Ethernet 的工作模式,如果想要切换成infiniband模式,参考如下链接:

https://community.mellanox.com/s/article/howto-change-port-type-in-mellanox-connectx-3-adapter

查看当前工作模式:

sudo /sbin/connectx_port_config -s

输入以下命令切换工作模式:

sudo /sbin/connectx_port_config

如果提示如图,说明不支持infiniband模式,否则,就切换成功了,再次使用一下命令可以验证:


原文链接:https://blog.csdn.net/bandaoyu/article/details/115906185


1、常规 IB 监视命令

ibv_asyncwatch 监视 InfiniBand 异步事件
ibv_devices or ibv_devinfo 列举 InfiniBand 设备或设备信息
ibv_rc_pingpong、ibv_srq_pingpong 或 ibv_ud_pingpong 使用 RC 连接、SRQ 或 UD 连接测试节点之间的连通性
mckey 测试 RDMA CM 多播设置和简单数据传输
rping 测试 RDMA CM 连接并尝试 RDMA ping
ucmatose 测试 RDMA CM 连接并尝试简单 ping
udaddy 测试 RDMA CM 数据报设置并尝试简单 ping
 

2、常规 IB 性能测试命令

rdma_client 或rdma_server 或rdma_xclient或 rdma_xserver 测试 RDMA 写处理确定流带宽或等待时间
ib_read_bw 或 ib_read_lat 测试 RDMA 读处理确定带宽或等待时间
ib_send_bw 或 ib_send_lat 测试 RDMA 发送处理确定带宽或等待时间
ib_write_bw 或 ib_write_bw_postlist 测试 RDMA 写处理,确定一次显示一个 I/O 请求的带宽或显示一系列 I/O 请求的发布列表带宽
ib_write_lat 测试 RDMA 写处理确定等待时间
ib_clock_test 测试系统时钟准确性
qperf 测量插槽与 RDMA 性能
RDS 监视与测试工具
rds-info 显示 RDS 内核模块信息
rds-ping 确定基于 RDS 的远程节点是否可访问
rds-stress 在基于 RDS 插槽的进程间发送消息
 

3、光纤网络诊断工具

iblinkinfo.pl 或 iblinkinfo 显示光纤网络中所有链路的链路信息
sminfo 查询 IB SMInfo 属性
ibstat 或 ibsysstat 查询 InfiniBand 设备状态或 IB 地址上的系统状态
perfquery or saquery 查询 IB 端口计数器或 sIB 子网管理属性
ibdiagnet 执行整个光纤网络诊断检查
ibcheckerrors 或 ibcheckerrs 验证 IB 端口(或节点)或 IB 子网并报告错误
ibaddr 查询 InfiniBand 的一个地址或多个地址
ibnetdiscover 搜索远程 InfiniBand 拓扑
ibping 验证 IB 节点之间的连通性
ibportstate 查询 IB 端口的物理端口状态和链接速度
ibroute 显示 InfiniBand 交换机转发表
ibtracert 跟踪 IB 路径
smpquery 或 smpdump 查询或转储 IB 子网管理属性
ibchecknet, ibchecknode, 或 ibcheckport 验证 IB 子网、节点或端口并报告错误
ibcheckportstate, ibcheckportwidth, ibcheckstate, or ibcheckwidth 验证已链接但不活动的 IB 端口、面向 1x (2.0 Gbps) 链路带宽的端口、IB 子网中已链接但不活动的端口或 IB 子网中的 lx 链路
ibclearcounters or ibclearerrors 对 IB 子网中的端口计数器或错误计数器进行清零
ibdatacounters or ibdatacounts 查询 IB 子网中的数据计数器或 IB 端口数据计数器
ibdiscover.pl 注释并比较 IB 拓扑
ibcheckerrors 或 ibcheckerrs 验证 IB 端口(或节点)或 IB 子网并报告错误
ibchecknet, ibchecknode, 或 ibcheckport 验证 IB 子网、节点或端口并报告错误
ibhosts 显示拓扑中的 IB 主机节点
ibnodes 显示拓扑中的 IB 节点
ibprintca.pl 显示来自 ibnetdiscover 输出的特定 CA 或 CA 列表
ibprintrt.pl 显示来自 ibnetdiscover 输出的特定路由器或路由器列表
ibprintswitch.pl 显示来自 ibnetdiscover 输出的特定交换机或交换机列表
ibrouters 显示拓扑中的 IB 路由器节点
ibstatus 查询 IB 设备的基本状态
ibswitches 显示拓扑中的 IB 交换机节点
ibswportwatch.pl
ibqueryerrors.pl 轮询特定交换机或端口上的计数器并报告更改信息速率
 

4、查询并报告非零 IB 端口计数器

ibprintswitch.pl 显示来自 ibnetdiscover 输出的特定交换机或交换机列表
set_nodedesc.sh 设置或显示针对 IB 主机控制器适配器 (HCA) 的节点描述字符串
dump2psl.pl 转储基于 opensm 输出文件的 PSL 文件,该输出文件用于信用循环检查
dump2slvl.pl 转储基于 opensm 输出文件的 SLVL 文件,该输出文件用于信用循环检查
ibis 针对 IB 管理带内服务的扩展 TCL shell


5、其常用指令
https://docs.oracle.com/cd/E19632-01/835-0783-03/bbggiggb.html#scrolltoc

更多命令:
https://docs.oracle.com/cd/E56344_01/html/E54075/makehtml-id-7.html


查看丢包,统计等信息
ip -s link show <if-name>
ethtool -S <if-name>
rx[i]_packets will be printed as rx0_packets for ring 0 and rx_packets for the software port 环0统计
watch -n 1 'ip -s link show' 查看丢包

while true;do ls /sys/class/net|while read i;do echo $i;date;ethtool -S $i;done;sleep 10;done

交换机用户手册 Mellanox MLNX-OS user Manual for vpi 4.40
查看接口统计: 
show interfaces




立即数:
IBV_WR_RDMA_WRITE_WITH_IMM
https://www.spinics.net/lists/linux-rdma/msg08336.html
https://www.rdmamojo.com/2013/01/26/ibv_post_send/
https://blog.csdn.net/bandaoyu/article/details/113253052
https://houbb.github.io/2019/11/20/rdma-02-based-system RDMA-02-基于RDMA高速网络的高性能分布式系统


IB软件堆栈, 驱动安装, 常用调试命令
https://docs.oracle.com/cd/E19244-01/820-7293-10/rfem3_software.html

博通RDMA以太网络控制器: Broadcom_Corporation_BCM57416_NetXtreme_E_10Gb_RDMA_Ethernet_Controller
Broadcom BCM57414 Ethernet 10/25Gb 2-port SFP28 Adapter for HPE
Broadcom NetXtreme-E RDMA Driver (bnxt_re) 博通网络驱动, Xtreme 极限

博通RDMA,内核软件: https://github.com/Broadcom/linux-rdma-nxt

英特尔® 以太网网络适配器 X722 具有 iWARP RDMA,可实现高数据吞吐量、低延迟工作负载和低 CPU 利用率。 X722 是软件定义存储解决方案、NVMe* over Fabric 解决方案和虚拟机迁移加速的理想选择
https://www.intel.com/content/www/us/en/ethernet-products/network-adapters/ethernet-x722-brief.html
rdma-core (用户空间的ibvers库,给应用程序编程提供接口)

modprobe irdma
yum erase rdma-core
rmmod irdma
modprobe irdma roce_ena=1
ethtool -i DEVNAME 查看pci总线与接口信息, 也可查看ofed驱动版本, ethtool -i ib17-0
devlink dev param show

内联INLINE:
【RDMA】IBV_SEND_INLINE和IBV_SEND_SIGNALED的原理|RDMA小消息通信性能优化 原创 https://blog.51cto.com/liangchaoxi/4058426
减少网卡DMA
rdma教程: https://github.com/StarryVae/RDMA-tutorial/blob/master/tutorial.md

nvidia关于如何诊断RDMA: https://enterprise-support.nvidia.com/s/article/How-To-Enable-Verify-and-Troubleshoot-RDMA

发现目标:
iscsiadm -m discovery -o new -o old -t st -I iser -p <ip:port> -l


MTT, 虚拟地址和物理地址转换, 如果page为4KB则最终的PA = (page number << 12)   (accessing VA & 0xfff), 

队列对中的最大发送工作请求数 = max_send_wr

查看rdma资源
rdma resource show qp

rdma注意事项和重点, https://docs.nvidia.com/networking/pages/viewpage.action?pageId=19798092, https://www.rdmamojo.com/2013/01/12/ibv_modify_qp/, https://insujang.github.io/2020-02-09/introduction-to-programming-infiniband/
1. fabric no sm(subnet manager)
2. lid是IB协议栈的二层属性, 所以在roce中查询显示为0, 子网中用lid(查询:ibv_query_port), 跨子网用gid
3. 查询不到路径, 建议使用rdma-cm(或cma代理,启用IPoIB)建连接, 它负责填充路径记录, 然而,有些应用程序更喜欢自己连接 QP,并通过套接字交换数据来决定使用哪些 QP 属性
4. roce流量统计不会显示在以太网设备中(硬件卸载, 不走以太网协议栈和驱动), roce和ib流量统计位置: /sys/class/infiniband/<device>/ports/<port number>/counters/, /sys/class/infiniband/<device name>/diag_counters 
5. 在 RoCE 中,应该在 QP 属性中为连接的 QP 配置 GRH,或者在地址句柄中为 UD QP 配置 GRH
6. 在 iWARP 中,应该仅使用通用 RDMA CM 代理 (CMA) 连接 QP
7. ibv_modify_qp 在UC和RC中,意味着与远端QP建立连接
8. sq和rq可使用不同的cq, 也可以为则会个那个qp设置一个cq
9. 编写RDMA程序大致很简单:生成一个QP和一个CQ(以及该操作所需的其他数据结构,后面会介绍),将QP连接到远程节点,生成工作请求(WR)和将其发布到 QP 中
10.编程模型, libibverbs api
libibverbs library provides high level userspace APIs to use Infiniband HCAs 3 4. With the APIs, the program runs as the following simplified description:
Create an Infiniband context (struct ibv_context* ibv_open_device())
Create a protection domain (struct ibv_pd* ibv_alloc_pd())
Create a completion queue (struct ibv_cq* ibv_create_cq())
Create a queue pair (struct ibv_qp* ibv_create_qp())
Exchange identifier information to establish connection 交换身份信息
  LID – Local Identifier, 16 bit addr. assigned to end nodes by subnet manager
  QPN – Queue Pair Number, identifier assigned to QP by HCA
  PSN – Packet Sequence Number, used by HCA to verify correct order of packages / detect package loss
  R_Key
  VADDR, address of memory region for peer to write into
Change the queue pair state (ibv_modify_qp()): change the state of the queue pair from RESET to INIT, RTR (Ready to Receive), and finally RTS (Ready to Send) 5
Register a memory region (ibv_reg_mr())
Exchange memory region information to handle operations
Perform data communication

11. ib_port是qp在host中用于通信,通过ibstat(安装infiniband-diags工具)查看数量和状态
12. 由于对等信息已经存储在 RTR 步骤,将状态更改为 RTS 不需要任何进一步的对等信息
13. 处理完成队列, 轮询(优选)和通知机制, 轮询通常更快(低延迟)用于检测,因为通知需要多次上下文切换、进程调度等
14. 提升性能 Performance, https://www.rdmamojo.com/2013/06/08/tips-and-tricks-to-optimize-your-rdma-code/
General tips 
• Avoid using control operations in data path 避免在IO路径中使用控制操作, ceph不满足(注册内存)
  - They will perform context switch 
  - They may allocate/free dynamic resources 
• Set affinity for process/task 
• Work with local NUMA node ceph设计上不满足
• Use MTU(power of 2) which provide best performance, port 2 will run with MTU of 1K, The RoCE's MTU values are 256 byte, 512 byte, 1024 byte, and 2K
• Register physical contiguous memory 
• UD is more scalable than RC 
Posting 
• Post multiple Work Request in one call 一次提交多个工作请求
• Avoid using many scatter/gather elements 避免使用多个分散聚集表sgl, sg_list = ceph不满足, ep->wrs->msg_wr.num_sge = 1, 多个可采用内联 IBV_SEND_INLINE
• Atomic operations are performance killers 避免原子操作
• Work with big messages 使用大消息
• Use selective signaling to reduce number of Work Completions 
• Inline data will provide better latency 使用内联降低时延, dma可直接读取负载数据, 减少dma次数
Polling 
• Read multiple Work Completion in one call 一次轮询多个完成事件
• Use polling to get low latency and Completion events to get lower CPU usage 
• When working with events: acknowledge multiple events at once 一次确认多个事件
15. ibv_fork_init, 性能问题: http://jiangzhuti.me/posts/ibv_fork_init原理,局限性与最佳实践
官方API: https://docs.nvidia.com/networking/display/RDMAAwareProgrammingv17/Initialization
ceph不满足


fabric 公共函数:  ofi.h: roundup_power_of_two, fi_get_aligned_sz
提供商矩阵: provider matrix to include EFA

默认情况下,Verbs 提供程序不提供分叉安全。 可要求货叉安全, 通过设置 IBV_FORK_SAFE 或 RDMAV_FORK_SAFE。 如果系统配置支持, 使用大页面,建议设置RDMAV_HUGEPAGES_SAFE。
有关更多详细信息,请参阅 ibv_fork_init(3)。

fabric大页检测, 获取大页: 
ofi_hugepage_enabled
  ofi_get_hugepage_size
  ofi_alloc_hugepage_buf
  ofi_unmap_anon_pages


获取设备信息:
/opt/h3c/bin/get-rdma-device-info.sh ib5e-0
time show_gids 280ms


gids
Use ibv_query_gid and ibv_find_gid_index functions defined in libibverbs to get the desired GID index.
You can refer to the following posts for details.
http://www.rdmamojo.com/2012/08/02/ibv_query_gid/
https://svn.openfabrics.org/svnrepo/ofw/gen1/trunk/ulp/libibverbs/src/verbs.cpp

union ibv_gid gid;

rc = ibv_query_gid(ctx, 1, 2, &gid);
if (rc) {
	fprintf(stderr, "Error, failed to query GID index %d of port %d in device '%s'n",
		2, 1, ibv_get_device_name(ctx->device));
	return -1;
}

IBV_EVENT_GID_CHANGE触发, 更新缓存

子网: https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/8/html/configuring_infiniband_and_rdma_networks/configuring-an-infiniband-subnet-manager_configuring-infiniband-and-rdma-networks
failed to start lsb
journalctl -xe
需要子网管理器才能建立卡上的链接。 可能有多个,在这种情况下,一个将充当控制器,而任何其他子网管理器将充当端口,在控制器子网管理器发生故障时接管
/etc/sysconfig/opensm
systemctl restart opensm

roce(RoCEv2):
参考(英伟达Nvidia): https://docs.nvidia.com/networking/pages/viewpage.action?pageId=12013422
fabric中不需要子网管理器(SM), 
RoCE 协议的直接扩展使流量能够在 IP 第 3 层环境中运行。 此功能是通过对 RoCE 数据包格式进行简单修改而获得的。 与 RoCE 中使用的 GRH 不同,IP 可路由 RoCE 数据包携带一个 IP 标头,允许穿越 IP L3 路由器和一个 UDP 标头(仅限 RoCEv2),用作 RDMA 传输协议数据包的无状态封装层。

提议的 RoCEv2 数据包使用明确区分数据报的众所周知的 UDP 目标端口值。 与使用 UDP 封装的其他协议类似,UDP 源端口字段用于携带不透明的流标识符,允许网络设备实现数据包转发优化(例如 ECMP),同时保持对协议标头格式细节的不可知。
此外,由于此更改只影响线路上的数据包格式,并且由于使用 RDMA 语义数据包是在 AP 下方生成和使用的事实,因此应用程序可以以完全透明的方式在任何形式的 RDMA 服务上无缝运行

修改roce模式: 参考: https://enterprise-support.nvidia.com/s/article/howto-configure-roce-v2-for-connectx-3-pro-using-mellanox-switchx-switches
cat /etc/modprobe.d/mlx4_1.conf
options mlx4_core roce_mode=2 rr_proto=23456
重启驱动: /etc/init.d/openibd restart
ifconfig eth2 11.11.5.1/24 up ; route add -net 11.11.0.0 -gw 11.11.5.2

ConnectX®-3 仅支持 RoCEv1,而 ConnectX®-3 Pro 同时支持 RoCEv1 和 RoCEv2。 可以使用 /etc/modprobe.d/mlx4_core.conf 文件中的“roce_mode”参数设置 RoCE 模式

ECMP (multi-path) - load sharing: 多路径负载均衡

支持RDMA_CM, 设置默认roce模式
mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/rdma_cm
mkdir mlx4_0
cd mlx4_0
echo RoCE V2 > default_roce_mode
cd ..
rmdir mlx4_0

查看mlx网卡配置: cat /sys/module/mlx5_ib/parameters/dc_cnak_qp_depth

基准测试(-R, 启用ROCE):
server
ib_write_bw -R -d mlx4_0 -i 1 --report_gbits -D 10

client
ib_write_bw -R -d mlx4_0 -i 1 --report_gbits 11.11.5.1 -D 10

gid:
对于支持两种 RoCE 模式的设备 (ConnectX®3 Pro) 上的端口,该表将被两个 GID 占用,它们具有相同的 GID 值但具有不同的类型。 条目中的网络设备是具有 GID 关联的 IP 地址的以太网设备。 GID 格式可以有两种类型; IPv4 和 IPv6。 IPv4 GID 是 IPv4 映射的 IPv6 地址,而 IPv6 GID 是 IPv6 地址本身。 与 IPv4 GID 关联的数据包的第 3 层报头将是 IPv4(对于 RoCEv2),对于与 IPv6 GID 关联的数据包和 RoCEv1 的 IPv4 GID 是 IPv6/GRH, 硬件中的条目数限制为每个端口 128, 

通过sysfs暴露gid:
/sys/class/infiniband/{device}/ports/{port}/gids/{index}
/sys/class/infiniband/{device}/ports/{port}/gid_attrs/types/{index}
/sys/class/infiniband/{device}/ports/{port}/gid_attrs/ndevs/{index}

要将 RC/UC QP(连接的 QP)从 INIT 修改为 RTR,必须给出地址向量 (AV)。 除了其他属性之外,AV 应该为 QP 的源 GID 指定端口的 GID 表的索引。 该索引中的 GID 类型将用于设置 QP 的 RoCE 类型

rdma-cm:
只需要传递ip即可, 它会自动决定使用哪个gid, 
查看设备和端口的roce模式
cma_roce_mode -d <dev> -p <port>
设置roce模式: cma_roce_mode -d <dev> -p <port> -m <1|2>

roce Lossless 无损配置:
Priority Flow Control (PFC), 使用优先级流控, 配置参考: 
https://manualzz.com/doc/6580025/roce-with-priority-flow-control-application-guide
https://enterprise-support.nvidia.com/s/article/howto-run-roce-over-l2-enabled-with-pfc

global pause or Port Control Protocol (PCP) 

Direct Access Transport (DAT)
用户直接访问编程库 (uDAPL) 是一种标准 API,可通过 RDMA 互连 InfiniBand 和 RoCE 提升数据中心应用程序数据消息传递性能、可扩展性和可靠性。 uDAPL 接口由 DAT 协作定义。 DAT 1.2 和 2.0 规范的 uDAPL 参考实施包的发布时间与 OFED Open Fabrics (www.openfabrics.org) 软件堆栈的发布时间一致

NVIDIA OFED 是一个单一的虚拟协议互连 (VPI) 软件堆栈,它在支持以下服务器上行链路的所有 NVIDIA 网络适配器解决方案中运行

vlan:
802.1q, PCP in 802.1q Headers
modprobe 8021q
vconfig add eth2 7

rdma_cm测试:
server: ucmatose
client: ucmatose -s 20.4.3.219

RoCE Link Aggregation (RoCE LAG): 链路聚合, RoCE LAG 是一种用于模拟 IB 设备以太网绑定的功能,仅适用于双端口卡
RoCE 链路聚合 (RoCE LAG) 为 mlx4 设备物理端口提供故障转移和链路聚合功能。 在这种模式下,只有一个 IB 端口(代表两个物理端口)暴露给应用层。 内核 4.0 是此功能正常运行的要求
查看链路聚合配置: /sys/bus/pci/drivers/mlx5_core/<bdf>/ roce_lag_enable

ECMP, Equal Cost Multi-Path:
等价多路径 (ECMP) 是一种网络路由策略,它使来自相同流或会话的流量数据包(具有相同目标 IP 地址和/或源的流量)能够以相同的成本在多条最佳路径上传输。

ttl:
/sys/class/infiniband/<dev>/tc/<port>/ttl 0-255

Nvidia OFED:
用户手册: https://docs.nvidia.com/networking/display/MLNXOFEDv562090/Introduction
所有 NVIDIA 网络适配卡都与基于 OpenFabrics 的 RDMA 协议和软件兼容,并受到主要操作系统发行版的支持。
NVIDIA OFED 已通过以下产品认证:
NVIDIA Messaging Accelerator (VMA™) 软件:套接字加速库,可为基于套接字的标准应用程序执行操作系统旁路。
请注意,VMA 支持与 NVIDIA OFED 支持分开提供。 有关详细信息,请参阅 VMA 文档 (https://docs.nvidia.com/networking/category/vma)。
NVIDIA Unified Fabric Manager (UFM®) 软件:用于管理要求苛刻的横向扩展计算结构环境的强大平台,构建于 OpenSM 行业标准路由引擎之上。
Fabric Collective Accelerator (FCA)——FCA 是一个 NVIDIA MPI 集成软件包,它利用 CORE-Direct 技术实现 MPI 集体通信。

中间核心层:Mid-layer Core
核心服务包括管理接口(MAD)、连接管理器(CM)接口和子网管理员(SA)接口。 该堆栈包括用于用户模式和内核应用程序的组件。 核心服务在内核中运行,并为动词、CM 和管理向用户模式公开接口。

消息传递接口 (MPI) 是一种库规范,支持开发并行软件库以利用并行计算机、集群和异构网络。 NVIDIA OFED 包括以下基于 InfiniBand 的 MPI 实现:
Open MPI——Open MPI Project 的开源 MPI-2 实现
NVIDIA OFED 还包括 MPI 基准测试,例如 OSU BW/LAT、Intel MPI BeBenchmark 和 Presta。

诊断工具:
ibutils—NVIDIA diagnostic utilities, 文档: https://www.mankier.com/package/ibutils
infiniband-diags—OpenFabrics Alliance InfiniBand diagnostic tools
NVIDIA 固件工具 (MFT)

软件包内容, 软件组件:


模块级别, 驱动配置: mlx5_core 模块

最大工作请求, max_wr:
通常,应用程序需要在尝试创建资源之前查询设备功能。 应用程序必须能够在具有不同功能的不同设备上运行。
具体来说,用户在创建QP时,需要指定QP支持的最大完成工作请求数。 此值不应超过查询的功能。 然而,即使您指定了一个不超过查询能力的数字,动词仍然会失败,因为一些其他因素(例如请求的分散/聚集条目的数量或所需的内联数据的大小)会影响最大可能的工作 要求。 因此,应用程序应该尝试减小此大小(减半是一个很好的新值)并重试直到成功

基准测试:  sysstat, vmstat, iostat, mpstat, dstat

发送-绕过缓存拷贝, 建议off
ethtool --show-offload eth1 | grep tx-nocache-copy

numa:
查看映射: mst status -v
cat /sys/class/net/ens785f0/device/numa_node
cat /sys/class/net/ens817/device/numa_node

lspci -D | grep Mellanox
cat /sys/devices/pci0000:00/0000:00:05.1/numa_node
在大多数情况下,如果适配器安装在以 8 开头的 PCI 地址(例如:81),它将位于 NUMA 1。如果它以 0 开头(例如:05),它将位于 NUMA 0

查看cpu映射: cat /sys/devices/system/node/node0/cpulist
查看位图: cat /sys/devices/system/node/node0/cpumap

设置亲和性: 
taskset -p 45118
taskset -cp 0-13,28-41 45118
taskset -c 0-13,28-41 ib_send_bw &

网卡性能调优: https://enterprise-support.nvidia.com/s/article/performance-tuning-for-mellanox-adapters

编程指南, 术语: https://docs.nvidia.com/networking/display/RDMAAwareProgrammingv17/Glossary

prefix “ibv_exp” (known as “experimental verbs”): 实验性API

用户空间 RDMA 子系统(称为 RDMA-Core)

Outstanding Work Request 等待轮询的WR,  WR which was posted to a work queue and its completion was not polled

IB定义:
InfiniBand (IB) 是一种高速、低延迟、低 CPU 开销、高效且可扩展的服务器和存储互连技术。 InfiniBand 的关键功能之一是它对本机远程直接内存访问 (RDMA) 的支持。 InfiniBand 支持服务器之间以及服务器与存储之间的数据传输,而无需主机 CPU 参与数据路径。 InfiniBand 使用 I/O 通道进行数据通信(每个主机最多 1600 万个),其中每个通道提供虚拟化 NIC 或 HCA 的语义(安全、隔离等)。 InfiniBand 提供各种技术或解决方案,速度范围从每个端口 10Gb/s (SDR) 到 56Gb/s (FDR),使用铜缆和光纤连接。 InfiniBand 的效率和可扩展性使其成为世界领先的高性能计算、云、Web 2.0、存储、数据库和金融数据中心和应用程序的最佳性能和成本/性能互连解决方案。 InfiniBand 是一种标准技术,由 IBTA 组织定义和指定。

IP 应用程序能够使用 IB 上的 IP (IPoIB) 或 IB 上的以太网 (EoIB) 或 RDS ULP 在 InfiniBand 结构上运行。 通过 iSER、SRP、RDS、NFS、ZFS、SMB 等支持存储应用程序。 MPI 和 Network Direct 也都是受支持的 ULP,但不在本文档的范围内

立即数发送: 可选地,立即数的 4 字节值可以与数据缓冲区一起传输。 此立即值作为接收通知的一部分提供给接收方,并且不包含在数据缓冲区中, 单端读和写, 远端是无感知的

RC, QP一对一, 可靠连接, 类似tcp

异步事件:
网络适配器可以发送异步事件来通知软件有关系统中发生的事件。有两种类型的异步事件:
附属事件:个人对象发生的事件(CQ、QP、SRQ)。 这些事件将被发送到特定的进程。
Unaffiliated events:全局对象发生的事件(网络适配器,端口错误)。 这些事件将被发送到所有进程。

Address Vector
地址向量是描述从本地节点到远程节点的路由的对象。 在每个 UC/RC QP 中,QP 上下文中都有一个地址向量。 在 UD QP 中,地址向量应该在每个 post SR 中定义。 struct ibv_ah 用于实现地址向量。

内存注册是一种机制,它允许应用程序使用虚拟地址向网络适配器描述一组虚拟连续的内存位置或一组物理连续的内存位置作为虚拟连续的缓冲区。
注册过程固定内存页面(以防止页面被换出并保持物理 <-> 虚拟映射)。 在注册期间,操作系统检查注册块的权限。 注册过程将虚拟到物理地址表写入网络适配器。 注册内存时,会为该区域设置权限。 权限是本地写入、远程读取、远程写入、原子和绑定。 每个 MR 都有一个远程密钥和一个本地密钥 (r_key, l_key)。 本地 HCA 使用本地密钥访问本地内存,例如在接收操作期间。 将远程密钥提供给远程 HCA,以允许远程进程在 RDMA 操作期间访问系统内存。 同一个内存缓冲区可以注册多次(即使具有不同的访问权限)并且每次注册都会产生一组不同的密钥。

典型编程示例:
一个典型应用程序的结构如下。 实现每个步骤的编程示例中的函数以粗体表示。

获取设备列表;
首先,您必须检索本地主机上可用 IB 设备的列表。 此列表中的每个设备都包含一个名称和一个 GUID。 例如,设备名称可以是:mthca0、mlx4_1。
由 resources_create 在编程示例中实现
打开请求的设备;
遍历设备列表,根据设备的 GUID 或名称选择设备并打开它。
由 resources_create 在编程示例中实现
查询设备能力;
设备功能允许用户了解所支持的功能(APM、SRQ)和打开的设备的功能。
由 resources_create 在编程示例中实现
分配一个保护域来包含你的资源;
保护域 (PD) 允许用户限制哪些组件只能相互交互。 这些组件可以是 AH、QP、MR、MW 和 SRQ。
由 resources_create 在编程示例中实现
注册一个内存区域;
VPI 仅适用于注册内存。 可以注册在进程的虚拟空间中有效的任何内存缓冲区。 在注册过程中,用户设置内存权限并接收本地和远程密钥(lkey/rkey),这些密钥稍后将用于引用此内存缓冲区。
由 resources_create 在编程示例中实现
创建一个完成队列(CQ);
CQ 包含已完成的工作请求 (WR)。 每个 WR 都会生成一个完成队列条目 (CQE),放在 CQ 上。 CQE 将指定 WR 是否成功完成。
由 resources_create 在编程示例中实现
创建一个队列对(QP);
创建 QP 也会创建关联的发送队列和接收队列。 由 resources_create 在编程示例中实现
调出一个QP;
创建的 QP 仍然不能使用,直到它通过几个状态转换,最终进入准备发送 (RTS)。 这提供了 QP 用来发送/接收数据所需的信息。
在编程示例中由 connect_qp、modify_qp_to_init、post_receive、modify_qp_to_rtr 和 modify_qp_to_rts 实现。
发布工作请求并投票完成;
使用创建的 QP 进行通信操作。
通过 post_send 和 poll_completion 在编程示例中实现。
清理;
按照创建它们的相反顺序销毁对象:
删除QP
删除CQ
注销 MR
释放 PD
关闭设备
由 resources_destroy 在编程示例中实现。


Netlink用于在内核和用户态, 内核和内核间传输消息, netlink - communication between kernel and user space (AF_NETLINK)
https://man7.org/linux/man-pages/man7/netlink.7.html

max_wr, max_sge设置的较小对性能有提升, 最好使用较低的可能值,因为涉及缓存(例如:用于地址转换)


InfiniBand应用:
在高并发和高性能计算应用场景中,当客户对带宽和时延都有较高的要求时,可以采用IB组网:前端和后端网络均采用IB组网,或前端网络采用10Gb以太网,后端网络采用IB。由于IB具有高带宽、低延时、高可靠以及满足集群无限扩展能力的特点,并采用RDMA技术和专用协议卸载引擎,所以能为存储客户提供足够的带宽和更低的响应时延。
IB目前可以实现以及未来规划的更高带宽工作模式有(以4X模式为例):
·SRD (Single Data Rate):单倍数据率,即8Gb/s
·DDR (Double Data Rate):双倍数据率,即16Gb/s
·QDR (Quad Data Rate):四倍数据率,即32Gb/s
·FDR (Fourteen Data Rate):十四倍数据率,56Gb/s
·EDR (Enhanced Data Rate):100 Gb/s
·HDR (High Data Rate):200 Gb/s
·NDR (Next Data Rate):1000 Gb/s 

NVIDIA Mellanox InfiniBand NDR产品是第7代的InfiniBand产品,利用100Gb/s的PAM4 Serdes技术, 实现了400Gb/s的单端口传输带宽, 是上一代产品的两倍, 同时通过添加更多、更强大的加速引擎,实现了更强大的计算和通信能力

可扩展的分层聚合和缩减协议

如果网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术(和普通的 DMA 有所不同),我们可以进一步减少通过 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程。你可以在你的 Linux 系统通过下面这个命令,查看网卡是否支持 scatter-gather 特性
ethtool -k br0 | grep scatter-gather

Internet Wide-area RDMA Protocol (iWARP)

rdma在ceph中的优势
避免发送方和接收方的内存复制,为应用程序提供最小的往返延迟和最低的 CPU 开销。
数据从网络移动到目标计算机中的应用程序内存区域,而不涉及其操作系统和网络输入/输出 (I/O) 堆栈。
RDMA 协议将数据作为消息传输,而 TCP 套接字将数据作为字节流传输。RDMA 避免了 TCP 流中使用的标头消耗额外的网络带宽和处理。
RDMA协议天然是异步的;消息传输期间不需要阻塞

ucx_info -d|grep Transport

查看驱动
ibv_devinfo
lspci | grep Mellanox
FI_PROVIDER=mlx

立即数, 带立即数的写
Request: support for RDMA write with immediate data, https://github.com/openucx/ucx/issues/2188

curve, RDMA网络通讯的使用
https://github.com/opencurve/incubator-brpc/blob/ucx_am/docs/cn/ucx.md
https://github.com/ssbandjl/brpc/blob/master/docs/cn/rdma.md


rpm -q libibverbs
rpm -q rdma-core
lspci -vvv | grep NVIDIA
nvidia-smi | sed -n 3p
ucx_info -d

ofi vs ucx, https://github.com/ARCHER2-HPC/performance_ofi-ucx
OpenFabrics 或 UCX 传输协议的选择会对应用程序性能产生很大影响
• 对于使用 MPI_Alltoallv 集体操作的基准,观察到特别大的影响
• 在这些情况下,使用 UCX 通常比 OFI 提供更好的性能/缩放
• 在 OSU MPI_Alltoallv 微基准测试中看不到效果
• 依赖点对点 MPI 例程的基准显示 OFI 和 UCX 之间的性能差异要小得多

export UCX_NET_DEVICES=`ibdev2netdev | grep Up | awk '{print $1":"$3}'`
export NCCL_IB_HCA=$UCX_NET_DEVICES

ulimit -l unlimited
echo "run $UCX_NET_DEVICES $@"
$@

High Performance Compute Availability (HPCA) Benchmark

driver 驱动
./mlnxofedinstall --without-depcheck --add-kernel-support --kmp --force

验证无损配置, 压力测试
// Run on host S1
# ib_write_bw -R --report_gbits --port=12500 -D 10 & ib_write_bw -R --report_gbits --port=12510 -D 10

// Run on host S2
# ib_write_bw -R --report_gbits 11.11.100.1 --port=12500 -D 10

// Run on host S3
# ib_write_bw -R --report_gbits 11.11.100.1 --port=12510 -D 10

switch: show interfaces ethernet 1/1 counters priority 3
server: ethtool -S ib17-1|grep prio_3

ibv_wr_rdma_write, ibv_wr_rdma_write_imm 提交rdma工作请求, _imm 版本导致远程端获得包含 32 位立即数据的 IBV_WC_RECV_RDMA_WITH_IMM


安装驱动, mellanox
yum install elfutils-libelf-devel python-devel
yum install -y rpm-build
yum install -y createrepo
yum install -y patch
./mlnxofedinstall  --add-kernel-support --with-nvmf --force -vvv

IBV_SEND_FENCE(发送栅栏) - 为此 WR 设置围栏指示器。 这意味着此 WR 的处理将被阻止,直到所有先前发布的 RDMA 读取和原子 WR 完成。 仅对传输服务类型为 IBV_QPT_RC 的 QP 有效
发送标记, FLAG:
IBV_SEND_FENCE - 为此 WR 设置围栏指示器。 这意味着此 WR 的处理将被阻止,直到所有先前发布的 RDMA 读取和原子 WR 完成。 仅对传输服务类型为 IBV_QPT_RC 的 QP 有效
IBV_SEND_SIGNALED - 设置此 WR 的完成通知指示器。 这意味着如果 QP 是用 sq_sig_all=0 创建的,那么当这个 WR 的处理结束时,将生成一个 Work Completion。 如果 QP 是使用 sq_sig_all=1 创建的,则此标志不会有任何影响
IBV_SEND_SOLICITED - 为此 WR 设置请求的事件指示符。 这意味着当此 WR 中的消息将在远程 QP 中结束时,将为其创建请求事件,如果在远程端用户正在等待请求事件,它将被唤醒。 仅与立即操作码的发送和 RDMA 写入相关
IBV_SEND_INLINE - sg_list 中指定的内存缓冲区将内联放置在发送请求中。 这意味着低级驱动程序(即 CPU)将读取数据而不是 RDMA 设备。 这意味着 L_Key 不会被检查,实际上那些内存缓冲区甚至不需要注册,它们可以在 ibv_post_send() 结束后立即重用。 仅对 Send 和 RDMA Write 操作码有效

https://ofiwg.github.io/libfabric/v1.5.3/man/fi_rma.3.html, fi_rma
FI_FENCE 指示请求的操作(也称为防护操作)被推迟,直到针对同一目标端点的所有先前操作都已完成。

lossy rdma 有损rdma, https://www.usenix.org/conference/nsdi23/presentation/wang-zilong


如果 CQ 大小超过 ibv_device_attr->max_cqe,verbs可能会抛出错误 OFI 不会向应用程序公开 CQ 大小,因为在提供程序中修复该问题比在处理该问题的应用程序中更好。 修复方法是打开多个动词 CQ 并对它们进行负载平衡“MSG EP 到 CQ 绑定”*,以避免任何 CQ 溢出。 类似于: num_qp_per_cq = ibv_device_attr->max_cqe / (qp_send_wr   qp_recv_wr)
cq->cq = ibv_create_cq(domain->verbs, size, cq, cq->channel

网卡能力:
	max_qp:				131072
	max_qp_wr:			32768
	cq moderation caps:
		max_cq_count:	65535
		max_cq_period:	4095 us


rdma res: 查看消耗的qp数

ibv_wc_status_str: wc状态转字符串

晓兵(ssbandjl)

博客: https://logread.cn | https://blog.csdn.net/ssbandjl | https://cloud.tencent.com/developer/user/5060293/articles

DAOS汇总: https://cloud.tencent.com/developer/article/2344030

公众号: 云原生云

晓兵技术杂谈(系列)

https://cloud.tencent.com/developer/user/5060293/video

0 人点赞