【RDMA】6. RDMA之Memory Region
Memory Region
摘自: RDMA性能优化经验浅谈(一)https://zhuanlan.zhihu.com/p/522332998
RDMA的网卡(下文以RNIC指代,RNIC(NIC=Network Interface Card ,网络接口卡、网卡,RNIC即 RDMA Network Interface Card))通过DMA来读写系统内存,由于DMA只能根据物理地址访问,所以RNIC需要保存一份目标内存区域的虚拟内存到物理内存的映射表,这个映射表被存储在RNIC的Memory Translation Table(MTT)中。同时,由于目前RDMA的访问大都基于Direct Cache Access,不支持page-fault,所以我们还需要保证目标内存区域是被pagelock住以防止操作系统将这部分内存页换出。
总结一下就是,当我们使用RDMA来访问一块内存的时候,这部分内存首先要被pagelock,接着我们还需要把这块内存虚拟地址到逻辑地址的映射表发送给RNIC用于后续的访问查找,这个过程就叫Memory Registeration,这块被注册的内存就是Memory Region。同时我们注册内存的时候需要指定这块内存的访问权限,RNIC将这个访问权限信息存储在Memory Protection Tables(MPT)中用于用户请求时的权限验证。
MTT和MPT被存储在内存中,但是RNIC的SRAM中会进行缓存。当RNIC接收到来自用户的READ/WRITE请求的时候,首先在SRAM中的缓存中查找用户请求的目标地址对应的物理地址以及这块地址对应的访问权限,如果缓存命中了,就直接基于DMA进行操作,如果没有命中,就得通过PCIe发送请求,在内存的MTT和MPT中进行查找,这带来了相当的额外开销,尤其是当你的应用场景需要大量的、细粒度的内存访问的时候,此时RNIC SRAM中的MTT/MPT命中缺失带来的影响可能是致命的。
Memory Region的注册是一个耗时的操作,但大部分情况下,我们都只需要在最开始的时候做一次或者多次。现在也有不需要注册MR基于on-demand paging的方式来访问的,比如AWS的EFA协议。但今天先不展开这块的内容,因为这块更多是Unified Memory这个话题下的,之后我可能会把这个和GPU的UVM放在一起介绍下,因为他们的核心原理其实是一样的。
原文:6. RDMA之Memory Region--https://zhuanlan.zhihu.com/p/156975042
我们假设一种场景,同时也顺便温习一下RDMA WRITE操作的流程:
如下图所示,A节点想要通过IB协议向B节点的内存中写入一段数据,上层应用给本节点的RDMA网卡下发了一个WQE,WQE中包含了源内存地址、目的内存地址、数据长度和秘钥等信息,然后硬件会从内存中取出数据,组包发送到对端网卡。B节点的网卡收到数据后,解析到其中的目的内存地址,把数据写入到本节点的内存中。
那么问题来了,APP提供的地址都是虚拟地址(Virtual Address,下文称VA),经过MMU的转换才能得到真实的物理地址(Physical Address,下文称PA),我们的RDMA网卡是如何得到PA从而去内存中拿到数据的呢?就算网卡知道上哪去取数据,如果用户恶意指定了一个非法的VA,那网卡岂不是有可能被“指使”去读写关键内存?
为了解决上面的问题,IB协议提出了MR的概念。
MR是什么
MR全称为Memory Region,指的是由RDMA软件层在内存中规划出的一片区域,用于存放收发的数据。IB协议中,用户在申请完用于存放数据的内存区域之后,都需要通过调用IB框架提供的API注册MR,才能让RDMA网卡访问这片内存区域。由下图可以看到,MR就是一片特殊的内存而已:
在对IB协议进行相关描述时,我们通常称RDMA硬件为HCA(HCA:在Infiniband/RoCE规范中,将RDMA网卡称为HCA,全称为Host Channel Adapter, 宿主通道适配器),IB协议中对其的定义是“处理器和I/O单元中能够产生和消耗数据包的IB设备”,为了与协议保持一致,我们在包括本文及之后的文章中都称硬件部分为HCA。
为什么要注册MR
下面我们来看一下MR是如何解决本文开篇提出的两个问题的:
1. 注册MR以实现虚拟地址与物理地址转换
我们都知道APP只能看到虚拟地址,而且会在WQE中直接把VA传递给HCA(既包括本端的源VA,也包括对端的目的VA)。现在的CPU都有MMU和页表这一“利器”来进行VA和PA之间的转换,而HCA要么直接连接到总线上,要么通过IOMMU/SMMU做地址转换后连接到总线上,它是“看不懂”APP提供的VA所对应的真实物理内存地址的。
所以注册MR的过程中,硬件会在内存中创建并填写一个VA to PA的映射表,这样需要的时候就能通过查表把VA转换成PA了。我们还是提供一个具体的例子来讲一下这个过程:
现在假设左边的节点向右边的节点发起了RDMA WRITE操作,即直接向右节点的内存区域中写入数据。假设图中两端都已经完成了注册MR的动作,MR即对应图中的“数据Buffer”,同时也创建好了VA->PA的映射表。
- 首先本端APP会下发一个WQE给HCA,告知HCA,用于存放待发送数据的本地Buffer的虚拟地址,以及即将写入的对端数据Buffer的虚拟地址。
- 本端HCA查询VA->PA映射表,得知待发数据的物理地址,然后从内存中拿到数据,组装数据包并发送出去。
- 对端HCA收到了数据包,从中解析出了目的VA。
- 对端HCA通过存储在本地内存中的VA->PA映射表,查到真实的物理地址,核对权限无误后,将数据存放到内存中。
再次强调一下,对于右侧节点来说,无论是地址转换还是写入内存,完全不用其CPU的参与。
2. MR可以控制HCA访问内存的权限
因为HCA访问的内存地址来自于用户,如果用户传入了一个非法的地址(比如系统内存或者其他进程使用的内存),HCA对其进行读写可能造成信息泄露或者内存覆盖。所以我们需要一种机制来确保HCA只能访问已被授权的、安全的内存地址。IB协议中,APP在为数据交互做准备的阶段,需要执行注册MR的动作。
而用户注册MR的动作会产生两把钥匙——L_KEY(Local Key)和R_KEY(Remote Key),说是钥匙,它们的实体其实就是一串序列而已。它们将分别用于保障对于本端和远端内存区域的访问权限。下面两张图分别是描述L_Key和R_Key的作用的示意图:
L_Key
R_Key
这里大家可能会有疑问,本端是如何知道对端节点的可用VA和对应的R_Key的?其实两端的节点在真正的RDMA通信之前,都会通过某些方式先建立一条链路(可能是Socket连接,也可能是CM连接)并通过这条链路交换一些RDMA通信所必须的信息(VA,Key,QPN等),我们称这一过程叫做“建链”和“握手”。我将在后面的文章中详细介绍。
除了上面两个点之外,注册MR还有个重要的作用:
3. MR可以避免换页
因为物理内存是有限的,所以操作系统通过换页机制来暂时把某个进程不用的内存内容保存到硬盘中。当该进程需要使用时,再通过缺页中断把硬盘中的内容搬移回内存,这一过程几乎必然导致VA-PA的映射关系发生改变。
由于HCA经常会绕过CPU对用户提供的VA所指向的物理内存区域进行读写,如果前后的VA-PA映射关系发生改变,那么我们在前文提到的VA->PA映射表将失去意义,HCA将无法找到正确的物理地址。
为了防止换页所导致的VA-PA映射关系发生改变,注册MR时会"Pin"住这块内存(亦称“锁页”),即锁定VA-PA的映射关系。也就是说,MR这块内存区域会长期存在于物理内存中不被换页,直到完成通信之后,用户主动注销这片MR。
好了,至此我们介绍完了MR的概念和作用,下一篇文章我将给大家介绍一下PD(Protection Domain,保护域)的概念。