@(RDMA翻译资料)
机器翻译,大概能理解。
VPI架构允许用户直接访问硬件。Mellanox提供动态加载库,通过VPI接口直接访问硬件。该文档包含verbs和相关的输入,输出,描述和功能性作为被暴露出的操作系统编程接口。
Note:编程手册manual和verbs仅在用户空间有效。参见内核空间verbs的头文件
通过verbs编程可以自定义和优化RDMA感知网络。
为了执行RDMA操作,在安装初期需要一些适当的权限才能建立到远程主机的链接。完成这个机制的Queue Pair (QP)。这相似于标准的IP栈,QP可以粗略的等价于socket。QP需要在链接的两端被初始化。通信管理(CM)通常用去改变QP 的优先级合QP的建立信息。
一旦QP被建立。verbs API可以执行RDMA I/O和原子操作。序列化发送合接受操作类似于socket I/O。
发送操作允许你发送数据到源端QP的接受队列。接收端必须预先设立一个接收缓冲用于接受数据,发送端无需额外的操作。
可选的,一个直接的4字节的值可以和数据buffer被一起传输。这个直接值作为接收段的通知的一部分而不包含在数据缓冲中。
该操作对应的操作是发送操作。接收端被通知数据将要到来,可能含有直接值。接收应用程序负责接收缓冲的建立和维护。
从远程主机读取一段内存。调用者指定远端虚拟地址当作本地内存地址进行复制。优先执行RDMA操作,远程主机应该提供合适的权限用于直接访问它的内存。一旦权限设立,RDMA读操作可以直接管理远程主机内存而不需要通知远程主机。对于RDMA读和RDMA写,在操作完成之前是不能感知的。
相识于RDMA读,数据写入远程主机。RDMA写操作不需要通知远程主机。RDMA write with immediate操作,无论怎样都会通知远程主机immediate value。
这些原子操作拓展到了RDMA操作
atomic FAA以原子操作的方式递增某一虚拟地址的值。该值优先返回给调用者。
atomic CAS将比较指定虚拟地址的值是否和指定值相同,相同则将新值存储在该地址对应的内存中。
当建立QP可以指定不同的传输操作。可用的操作选项如下表所示。RD不被当前API支持
Operation | UD | UC | RC | RD |
---|---|---|---|---|
Send (with immediate) | X | X | X | X |
Receive | X | X | X | X |
RDMA Write (with immediate) | X | X | X | |
RDMA Read | X | X | ||
Atomic: Fetch and Add/ Cmp and Swap | X | X | ||
Max message size | MTU | 1GB | 1GB | 1GB |
Queue Pair仅与另外一个QP相关联。
消息由其中一个QP的发送队列可靠的发送到其他QP的接收队列。
数据包按顺序发送。
一个RC链接相似于TCP链接。
Queue Pair仅与另外一个QP相关联。
带有错误的消息不会被传输重试,并且错误处理必须由更高级别的协议的协议提供支持。
QP可能传输和接收单包消息到其他UD QP。
SR被定义为 有多少数据从哪儿到哪儿,以怎样的发送方式进行发送。struct ibv_send_wr
用于描述SR
RR为非RDMA操作定义了要接收数据的缓冲区。 如果没有定义缓冲区并且发送器尝试发送操作或立即进行RDMA写入,则会发送接收未准备好(RNR)错误。 struct ibv_recv_wr用于实现RR。
完成队列(CQ)是一个对象,其中包含已发布到工作队列(WQ)的已完成工作请求。 每个completion都表示特定的WR已完成(既成功完成了WR,又成功完成了WR)。 完成队列是一种通知应用程序关于结束工作请求信息(状态,操作码,大小,来源)的机制。 CQ有n个完成队列条目(CQE)。 CQ创建时指定CQE的数量。 CQE被轮询时,将从CQ中删除。 CQ是CQE的FIFO。 CQ可以服务于发送队列,接收队列或两者。 来自多个QP的工作队列可以与单个CQ相关联。
struct ibv_cq用于实现CQ。
内存注册是一种机制,允许应用程序使用虚拟地址将一组虚拟连续的内存位置或一组物理连续的内存位置描述为虚拟连续的缓冲区。注册过程固定内存页面(以防止页面被换出并保持物理< - >虚拟映射)。在注册期间,操作系统检查注册块的权限。注册过程将虚拟物理地址表写入网络适配器。注册内存时,会为该区域设置权限。权限是本地写入,远程读取,远程写入,原子和绑定。每个MR都有一个远程和一个本地密钥(r_key,l_key)。本地密钥由本地HCA用于访问本地内存,例如在接收操作期间。远程密钥提供给远程HCA,以便在RDMA操作期间允许远程进程访问系统内存。相同的内存缓冲区可以多次注册(即使拥有不同的访问权限),每一次注册都会得到一组不同的密钥。 struct ibv_mr用于实现内存注册。
MW允许应用程序对其内存的远程访问进行更灵活的控制。Memory Windows适用于以下应用程序:
•希望以动态方式授予和撤销对注册地区的远程访问权限,并且性能损失低于使用注销/注册或重新注册。
•想要为不同的远程代理授予不同的远程访问权限和/或在已注册地区内的不同范围内授予这些权限。 将MW与MR关联的操作称为绑定。 不同的MW可以重叠相同的MR(具有不同访问权限的事件)。
地址向量是描述从本地节点到远程节点的路由的对象。 在每个UC / RC QP中,QP上下文中都有一个地址向量。 在UD QP中,地址向量应该在每个帖子SR中定义。 struct ibv_ah用于实现地址向量。
GRH用于在子网之间进行路由。 使用RoCE时,GRH用于在子网内进行路由,因此是强制性的。 强制使用GRH是为了使申请同时支持IB和RoCE。 在UD QP上使用全局路由时,接收缓冲区的前40个字节中将包含一个GRH。 该区域用于存储全局路由信息,因此可以生成适当的地址向量来响应接收到的数据包。 如果GRH与UD一起使用,那么RR应该总是有额外的40个字节可用于这个GRH。 struct ibv_grh用于实现GRH。
对象的组件只能彼此交互。 这些组件可以是AH,QP,MR和SRQ。 保护域用于将队列对与内存区域和内存窗口关联起来,作为启用和控制网络适配器访问主机系统内存的手段。 PD也用于将不可靠的数据报队列对与地址句柄相关联,作为控制对UD目的地的访问的手段。 struct ibv_pd用于实现保护域。
网络适配器可以发送异步事件以通知SW有关系统中发生的事件。 有两种类型的异步事件:附属事件:个人对象发生的事件(CQ,QP,SRQ)。 这些事件将被发送到一个特定的过程。 无关联事件:全局对象发生的事件(网络适配器,端口错误)。 这些事件将被发送到所有进程。
使用分散收集元素(收集/分散)数据,其中包括:地址:数据将从中收集或分散到的本地数据缓冲区的地址。 大小:将从该地址读取/写入的数据的大小。 L_key:注册到此缓冲区的MR的本地密钥。 struct ibv_sge实现分散聚集元素。
轮询CQ中的completion是获取有关发布的WR(发送或接收)的详细信息的方式。 如果在WR中有compleyion是错误状态,其余的completion将全部变坏(并且工作队列将被移至错误状态)。 每个没有完成(即被调查)的WR仍然是未完成的。 只有WR完成后,发送/接收缓冲区才可以被使用/重用/释放。 应始终检查完成状态。 CQE被轮询时,将从CQ中删除。 轮询通过ibv_poll_cq操作完成。
本文件提供了两个程序示例:
•第一份代码,RDMA_RC_example使用VPI berbs API,演示如何执行RC:发送,接收,RDMA读取和RDMA写入操作。
•第二份代码组播示例使用RDMA_CM berbs API来演示多播 UD。典型应用的结构如下。编程示例中的函数
实施每个步骤以粗体显示。
1. 获取设备列表;
首先,您必须检索本地主机上可用IB设备的列表。此列表中的每个设备都包含
名称和GUID。例如,设备名称可以是:mthca0,mlx4_1。
在编程示例中通过7.1.4 resources_create实现
2. 打开请求的设备;
遍历设备列表,根据其GUID或名称选择设备并将其打开。
1.7版RDMA感知编程概述
24 Mellanox Technologies
在编程示例中通过7.1.4 resources_create实现。
3. 查询设备功能;
设备功能允许用户了解支持的功能(APM,SRQ)和功能
打开的设备。
在编程示例中通过7.1.4 resources_create实现。
4. 分配保护域以包含您的资源;
保护域(PD)允许用户限制哪些组件只能与每个组件进行交互
其他。这些组件可以是AH,QP,MR,MW和SRQ。
在编程示例中通过7.1.4 resources_create实现。
5. 注册一个内存区域;
VPI仅适用于注册的内存。任何在进程的虚拟空间中有效的内存缓冲区
可以注册。在注册过程中,用户设置内存权限并接收本地
和远程密钥(lkey / rkey),这些密钥稍后将用于引用该存储器缓冲区。
在编程示例中通过7.1.4 resources_create实现。
6. 创建完成队列(CQ);
CQ包含完成的工作请求(WR)。每个WR将生成一个完成队列条目(CQE)
放在CQ上。 CQE将指定WR是否成功完成。
在编程示例中通过7.1.4 resources_create实现。
7. 创建队列对(QP);
创建QP还将创建关联的发送队列和接收队列。
在编程示例中通过7.1.4 resources_create实现。
8. 提出QP;
一个创建的QP在它经过几个状态转换之后仍然不能使用,最终会达到
准备发送(RTS)。这提供了QP用来发送/接收数据所需的信息。
在编程示例中通过7.1.6 connect_qp,7.1.7 modify_qp_to_init,7.1.8 post_receive,
7.1.10 modify_qp_to_rtr和7.1.11 modify_qp_to_rts。
9. 发布工作要求并投票完成;
使用创建的QP进行通信操作。
在编程示例中通过7.1.12 post_send和7.1.13 poll_completion实现。
10. Cleanup;
按照您创建它们的相反顺序销毁对象:
删除QP
删除CQ
注销MR
释放PD
关闭设备
在编程示例中通过7.1.14 resources_destroy实现。