| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> DMA、链式DMA、RDMA(精华讲解) -> 正文阅读 |
|
[网络协议]DMA、链式DMA、RDMA(精华讲解) |
一、DMA????????DMA全称Direct Memory Access,即直接存储器访问。CPU完成传输配置后,即可不在参与传输过程,由DMA控制器将数据从一个地址空间复制到另外一个地址空间。最长见的是本地DMA传输,如图1.1所示。 图1.1 ????????CPU设置好三要素(源、目的、大小)后,由DMA控制器将内存块A的内容拷贝到内存块B中。这是普通DMA传输,那么,PCIe设备是如何完成DMA传输的呢? ? 图1.2 ????????PCIe设备理想的DMA传输过程如图1.2所示,主机端(主片)对PCIe设备(从片)上DMA控制器配置后,由DMA控制将主机内存块A上数据搬运自身内存块B上。这里就有两个疑问了: ????????1.为什么是PCIe设备(从片)上的DMA控制器? ????????2.为什么是主机端(主片)来配置DMA控制器? ????????带着两个问题往下看。实际上PCIe总线上DMA过程如图1.3所示。 图1.3 ????????真实的数据搬运过程需要透过IOMMU(ARM架构为SMMU)并跨越PCI域,才能到达从片内存上。 ????????先回答第一个问题。一般情况X86平台的PCI控制器是不带DMA控制器的,普通的DMA只能完成本地总线上的数据搬运,而将本端数据搬运到从片上需要跨过PCI域,这是一般DMA控制器做不到的,所以使用从片上特殊的DMA控制器来完成这个过程。ARM平台虽然PCI控制器会带DMA控制器,但经常出现一主多从情况,所以为了提高传输效率和资源利用率,也多使用从片上的DMA。 ????????我们知道一般X86架构在没有开启IOMMU前,主片主存储域地址与PCI域地址是平行映射的,但开启IOMMU后就没有确定的映射关系了。比如,内存块A地址为0x100,平行映射后也是0x100,但开启IOMMU后,映射后的地址可能是0x900,也可能是0x200,即没有确定的映射地址。 ????????从片上DMA控制器想要把主片内存块A上数据搬运到从片内存块B上,就需要知道内存块A通过IOMMU映射后的地址,而这是从片无法知道的,所以一般都是由主片来配置从片DMA控制器,这便是第二个问题答案。 ????????另外从片也可能存在IOMMU,但设备要么是作为主片,要么作为从片,一般也只有主片会开启IOMMU。 ????????我们知道,DMA控制器所看到的都是物理地址,搬运的数据需要在连续的物理地址上,那么问题来了:如果内存紧张无法申请出连续的物理地址怎么办? ????????由这个问题引出本文第二部分——链式DMA! 二、链式DMA??? 为了更好讲解链式DMA传输过程,以某个PCIe的DMA过程为例。 主片申请一块4k对齐的内存空间存放数据,一般使用posix_memalign函数。如图2.1所示,可以看见虚拟内存连续,但物理内存离散,只有物理页D、E相邻。获取这段虚拟内存对应的物理页,将它们的描述结构保存在pages数组中,同时pin住这些物理页,避免存放数据的内存被系统换页到硬盘中,导致数据搬运过程中DMA控制器读取内存不是用户所预期的。 图2.1 ????????调用sg_alloc_table_from_pages 函数,传入上面获取的pages 数组,即可得到一个sg_tabel散列表,即图2.2右侧4个条目合起来称为sg_tabel散列表。 图2.2 ????????在填充sg_tabel散列表时,还会将相邻的物理页合并成一个条目,也就是物理页D与物理页E合并为条目DE。sg_table表对应结构体为: 图2.3 ????????每个块物理页对应一个条目scatterlist结构,其描述结构体为: 图2.4 ??? ????也就是说,现在这个sg_tabel散列表描述着这些物理页,其中dma地址是映射后的PCI域上地址,但这里还未得到。 ?? 未开启IOMMU????????????????????????? 开启IOMMU 图2.5 ????????调用pci_map_sg 函数完成离散映射,同时填充sg_table表中每个条目的dma地址,过程如图2.5所示,分为两种情况,在未开启IOMMU时,映射是平行映射,在开启IOMMU后,将会把离散的物理页映射成连续的PCI域空间,但并不会改变条目个数。至此sg_tabel离散映射表中即可准确描述数据内存在PCI域上地址。 图2.6 ????????如图2.6所示(未开启IOMMU)使用sg_tabel散列表填充从片的DMA描述子(与从片约定好的),也就是图2.6中间task块,其结构如下: 图2.7 ????????结构内部包含源地址、目标地址、大小及下一个task结构所在地址,就如同链表一样串在一块,所以称为链式DMA(需硬件支持)。 ????????让从片的BARX窗口映射从片特定地址,然后主片通过ioremap将BARX空间映射到虚拟内存空间,最后将填充好的DMA任务描述子拷贝到BARX虚拟空间,进而通过TLP总线事务传输至从片特定DDR地址上,过程如图2.6所示。 图2.8 ????????配置从片的DMA控制寄存器,从特定DDR地址上拿到DMA任务描述列表,即可开始数据搬运,如图2.8所示(未开启IOMMU)。注:从片上内存块依旧是连续物理内存块。 至此,链式DMA讲解结束,接下来讲解的是基于PCI域上链式DMA技术的RDMA技术。 三、RDMA????????本部分只解释核心名词和概念,尽量简化不必要内容,方便理解。 3.1 RDMA技术简介3.1.1 RDMA优劣势及应用场景????????RDMA是Remote Direct Memory Access的缩写,即远程直接数据存取。使用RDMA的优势如下:
????????既然RDMA技术这么好,为什么没能大规模普及?这就不能不说RDMA技术的劣势了,主要有两个:
????????目前,RDMA技术有三个比较好的应用方向,即存储、HPC(高性能计算)及数据中心,简要描述如下:
3.1.2 RDMA协议RDMA有三种协议,如下图所示: 图3.0 ????????图3.0较为直观的反映三种协议之间差异,再简单介绍一下它们。 Infiniband ????????2000年由IBTA(InfiniBand Trade Association)提出的IB协议是当之无愧的核心,其规定了一整套完整的链路层到传输层(非传统OSI七层模型的传输层,而是位于其之上)规范,但是其无法兼容现有以太网,除了需要支持IB的网卡之外,企业如果想部署的话还要重新购买配套的交换设备。 RoCE ????????RoCE从英文全称就可以看出它是基于以太网链路层的协议,v1版本网络层仍然使用了IB规范,而v2使用了UDP+IP作为网络层,使得数据包也可以被路由。RoCE可以被认为是IB的“低成本解决方案”,将IB的报文封装成以太网包进行收发。由于RoCE v2可以使用以太网的交换设备,所以现在在企业中应用也比较多,但是相同场景下相比IB性能要有一些损失。 iWARP ????????iWARP协议是IETF基于TCP提出的,但是因为TCP是面向连接的协议,而大量的TCP连接会耗费很多的内存资源,另外TCP复杂的流控等机制会导致性能问题,所以iWARP相比基于UDP的RoCE v2来说并没有优势(IB的传输层也可以像TCP一样保证可靠性),所以iWARP相比其他两种协议的应用不是很多。 ????????需要注意的是,上述几种协议都需要专门的硬件(RDMA网卡)支持。后续内容以RoCEv2协议进行讲解,但由于本部分只讲解原理,并不涉及底层实现,因此差异不大。 3.1.3 RDMA原理简介????????用一张图描述RDMA过程,如图3.1所示 图3.1 ????????HCA是宿主通道适配器,即RDMA网卡。相比于TCP/IP数据传输,RDMA传输可直接将本端用户态虚拟内存数据传输到对端用户态内存中,而不需要陷入内核! ????????这是如何实现的?通过本文前两部分讲解,我们知道带DMA引擎的PCI设备能够直接读写宿主机内存,如下图3.2所示。 图3.2 ??? ????如果DMA引擎从内存块A读取的数据不是放到内存块B,而是通过某种方法传递出去会怎样?如下图3.3所示。 图3.3 原理: ????????1.HCA是带DMA引擎的PCI设备,具有读写主机DDR能力。 ????????2.HCA是特殊网卡,除了普通网卡功能外,内部支持IB传输协议。 ????????HCA(RDMA网卡)读取本端数据后,在内部将数据按某些格式组包,再通过硬件接口传输到对端HCA上,由对端HCA解包后写入对端内存。值得注意的是,内存块A、B都是连续的虚拟内存,对应的物理内存可不一定连续。 ????????HCA硬件上天然支持RDMA传输,但软件上实现可不容易,先看下图。 图3.4 先简单介绍一下图3.4中模块: ????????libibverbs.so:rdma-core核心库 ????????libmlx5.so:用户态驱动,也是个动态链接库,实现厂商的驱动逻辑。 ????????ib_uverbs.ko:uverbs驱动 ????????ib_core.ko:RDMA子系统核心模块 ????????mlx5_ib.ko:RDMA硬件驱动程序(PCI设备驱动),负责直接和硬件交互。 ????????图3.4中有两条路径,为后续描述方便,称右侧路径为准备路径,称左侧路径为工作路径。可以看到,准备路径需要陷入内核态,而工作路径将绕过内核直接操作硬件,后续的讲解将从这两部分说明。上面说到,硬件天然支持RDMA传输,而软件的工作简要概括就是,通过某种方法告诉硬件三要素——源、目的、大小。 3.2 准备阶段????????准备阶段的部分工作就是获取三要素(源、目的、大小),但在此之前还需解决一个问题,在用户态下,用什么方法绕过内核,直接告诉硬件三要素? 3.2.1 获取通知方法????????以X86架构为例,我们知道BOIS启动阶段会在主机上为每个PCI设备分配BAR空间,如图3.5主存储域上橘黄色块,就是RDMA网卡的BAR空间。 ?图3.5 ????????RDMA设备驱动(如mlx5_ib.ko)匹配上设备后,会执行一系列初始化动作,同时保存设备BAR空间在主存储域上的地址。 ????????用户空间进程调用mmap函数分配一块虚拟内存,同时将调用到RDMA设备驱动的mmap函数,进而将主存储域上设备BAR空间映射到所申请的虚拟内存!所以在用户空间操作bar虚拟空间,即可操作RDMA网卡的某些寄存器或内存。 ????????在这块虚拟内存中,比较重要的是Doorbell,其实就是门铃的意思,是一种通知机制,当用户准备好工作请求之后,向Doorbell的地址中写一下数据,就等于敲了一下门铃,硬件就知道可以开始干活了。这便是用户态下的通知方法。 3.2.2 获取源????????通知方法有了,现在还需获取三要素,先来说源怎么获取,需要说明一下,这个源是一个集合,不仅仅是数据源地址。 图3.6 ??? ???如图3.6所示,用户申请一块长度为len的虚拟内存,执行RDMA注册函数,将会得到一个映射表,包含两部分,一个是sg_table记录着物理地址到pci域地址的转换关系,另一个是VA->PA映射表,记录着VA到PA的转换关系。VA->PA映射表很容易理解,sg_tabel获取过程和本文第二部分中描述类似,同样也会pin主内存,这里不再赘述。除此之外,还会获得lkey和rkey,一个是本端操作秘钥,另一个是本端赋予远端的操作秘钥。秘钥由两部分组成,低字节部分是真正的钥匙,高字节部分是本MR的映射表在缓存区的索引。 ????????每注册一个MR都会生成映射表和秘钥,这一系列映射表将放一个硬件知道的缓存区中,由秘钥的高字节索引。 ????????还有一个比较重要的东西,叫QP工作队列对,由SQ发送队列和RQ接收队列组成。QP是软件向硬件“发号施令”的媒介,由用户调用特定函数将其创建,如下图3.7所示。 图3.7 ????????除了创建QP外,还会创建QP的上下文QPC,即描述QP属性的一个结构,这个结构放在硬件知道的一段缓存区里,由QP号(QPN)索引,也就是说,可以有很多个QP,它们之间由QPN区分。值得注意的是,QPC中有一个GID存储区域,这个是存储对端GID的。 ????????GID是一个全局ID,由MAC地址和IP地址转换得来,根据GID就可以找到局域中唯一宿主机。调用专用函数可以获取本端的GID序列号。 ????????至此,源集合已准备好,有MR addr、len、lkey、QPN,再看看如何获取目的集合。 3.2.3 获取目的????????本端是无法直接获得对端基本信息的,所以需要通过某些方式,让两端建立通信交换基本信息。有两种方式:TCP/IP和RDMA CM,如下图3.8所示。 图3.8 ????????以socket交换方式为例,双方约定号消息格式,将需要传递的信息通过socket交换就好了。图3.8中LID是本端RDMA适配器激活后分配的ID,在本端唯一,而PSN是本端发送到对端第一个数据包序号,可以随机指定。信息交换完毕后即可关闭上述连接。 ????????至此,目的集合已经准备好,有raddr、rkey、rGID、rQPN,加r表示远端(对端)的意思。万事具备只欠东风。 3.3 工作阶段3.3.1 下发工作请求????????本端在下发工作请求前,还需要处理rQPN和rGID,这里以RC链接(类似于TCP链接)为例。本端需要将QP(节点A)与对端QP(节点x)绑定,在QPC中填入对端QPN,同时又因为是RC链接(点到点),还需在QPC中填入rGID。 ????????现在可以填写工作请求了,这个请求结构称为WQE,即工作请求元素,主要由三部分组成,控制头,远端地址和远端秘钥,本端地址、本端秘钥、数据大小,如下图3.9所示。 图3.9 ????????结合图3.5,将控制头拷贝到bar虚拟内存的Doorbell地址中(此处有防竞态机制),通过TLP总线事务传输到RDMA网卡内部,即敲响门铃,硬件就可以开始工作了。 ????????硬件通过控制头信息(QPN)找到对应的QPC,从而找到SQ中的WQE,通过DMA控制器把WQE搬运到内部解析,再通过lkey找到对应的映射表,然后将laddr转换获得数据所在物理页,最终从物理页取得数据组包,如下图3.10所示。 图3.10 ????????硬件还会在数据包中添加对端raddr和rkey,再从QPC中取得对端rGID,这样数据包才能到对端宿主机。对端接收到数据包后,根据rkey找到映射表,将raddr翻译,最后将数据写入对应离散物理页中,注意,这个过程cpu是不知道的,完全由RDMA网卡完成,不需要内核参与,在app侧看来,就是有人往某块连续的虚拟内存写了数据。 3.3.2 write流程简介在两方完成准备阶段并交换信息后,操作流程如下图3.11所示。 图3.11 将发送write请求的这侧称为请求端,另一侧称为响应端; ????????①请求端A下发write请求的WQE(src_addr、len、dst_addr、r_key),里面包含双方地址信息及秘钥; ????????②请求端A硬件(RDMA网卡)从SQ队列中取得WQE,获取源-目的-长度,这三要素; ????????③请求端A硬件(RDMA网卡)从内存src_addr地址取得长度为len的数据并组装成数据报文; ????????④请求端A硬件(RDMA网卡)将数据报文发送至响应端B; ????????⑤响应端B硬件检查秘钥无误后,根据rkey查找到映射表,将数据写至dst_addr地址对应的物理页中; ????????⑥响应端B硬件向请求端A硬件返回操作结果; ????????⑦请求端A硬件根据响应端B的反馈结果上报工作完成CQE,操作成功或失败,失败有错误码; ????????⑧请求端A的APP查看CQE获取工作完成情况。 其中CQ完成队列,存放的CQE是完成队列元素。 文章讲解完毕,觉得博主讲解不错就点个赞呗。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 19:25:35- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |