rdma 编程详解

1.相关名词解释

1.1 rdma-core

指开源RDMA用户态软件协议栈,(用户空间的驱动)包含用户态框架、各厂商用户态驱动、API帮助手册以及开发自测试工具等。

rdma-core在github上维护,我们的用户态Verbs API实际上就是它实现的。https://github.com/linux-rdma/rdma-core
 

1.2 kernel RDMA subsystem

开源的Linux内核中的RDMA子系统,(内核空间的驱动)包含RDMA内核框架及各厂商的驱动。

RDMA子系统跟随Linux维护,是内核的的一部分。一方面提供内核态的Verbs API,一方面负责对接用户态的接口。

1.3 OFED

全称为OpenFabrics Enterprise Distribution,是一个开源软件包集合,其中包含内核框架和驱动、用户框架和驱动、以及各种中间件、测试工具和API文档。

开源OFED由OFA组织负责开发、发布和维护,它会定期从rdma-core和内核的RDMA子系统取软件版本,并对各商用OS发行版进行适配。除了协议栈和驱动外,还包含了perftest等测试工具。

除了开源OFED之外,各厂商也会提供定制版本的OFED软件包,比如华为的HW_OFED和Mellanox的MLNX_OFED。这些定制版本基于开源OFED开发,由厂商自己测试和维护,会在开源软件包基础上提供私有的增强特性,并附上自己的配置、测试工具等。

以上三者是包含关系。无论是用户态还是内核态,整个RDMA社区非常活跃,框架几乎每天都在变动,都是平均每两个月一个版本。而OFED会定期从两个社区中取得代码,进行功能和兼容性测试后发布版本,时间跨度较大,以年为单位计。
 

1.4 Mellanox 的OFED下载安装

wget http://content.mellanox.com/ofed/MLNX_OFED-4.3-1.0.1.0/MLNX_OFED_LINUX-4.3-1.0.1.0-rhel7.2-x86_64.tgz

tar -xvf  MLNX_OFED_LINUX-4.3-1.0.1.0-rhel7.2-x86_64.tgz

cd MLNX_OFED_LINUX-4.3-1.0.1.0-rhel7.2-x86_64/

yum install lsof tcl tk libxml2-python -y

yum install createrepo.noarch -y

yum install python-devel -y

./mlnxofedinstall --dpdk --upstream-libs --add-kernel-support

安装完成后会提示:

/etc/init.d/openibd restart 

在执行restart时,可能需要首先执行(modprobe -rv  ib_isert rpcrdma ib_srpt),否则会restart失败

 安装完了需要restart

1.4.1安装过程中遇到的问题

 驱动下载地址:

驱动下载地址:
https://www.mellanox.com/page/products_dyn?product_family=26&mtag=linux_sw_drivers&ssn=e76bu2ei7i1dcniinql196evj4

Linux InfiniBand Drivers

安装过程中遇到的问题

解决方法

vi /usr/src/kernels/3.10.0-693.21.1.el7.x86_64/arch/x86/Makefile  166行,把ifneq到endif之间注释掉

 1.4.2 源码包

2. Verbs API 

广义的Verbs API主要由两大部分组成verbs和rdma_cm

Verbs API 操作RDMA的函数接口,也就是说业界的RDMA应用,要么直接基于这组API编写,要么基于在Verbs API上又封装了一层接口的各种中间件编写。(rdma_cm)

Verbs API向用户提供了有关RDMA的一切功能,典型的包括:注册MR、创建QP、Post Send、Poll CQ等等。

对于Linux系统来说,Verbs的功能由rdma-core和内核中的RDMA子系统提供,分为用户空间驱动的 Verbs api和内核空间驱动的Verbs api,分别用于用户态和内核态的RDMA 程序。
e0eba2a4af3d4e6179e178ec3a005632.png

2.1 rdma_cm和verbs的区别

 2.1.1 相互关系

1> rdma_cm依赖ib_verbs
2> ib_verbs和rdma_cm 都是Mellanox公司提供的两个动态链接库。(这两个库的API ,queue pair (QP)  类似于 TCP的sockets)
3> rdma_cm连接管理器库,包含了对ib_verbs的封装或具体化,通过verbs API 对硬件进行访问。
 

   rdma_post_send  = ibv_post_send(qp,wr.opcode=IBV_WR_SEND,bad_wr)  

   rdma_post_read  = ibv_post_send(qp,wr.opcode=IBV_WR_RDMA_READ ,bad_wr) 

  rdma_post_write  = ibv_post_send(qp,wr.opcode=IBV_WR_RDMA_WRITE,bad_wr) 

2.1.2 libibverbs和librdmacm的区别

在infiniband/verbs.h中,定义了ibv_post_send()和ibv_post_recv()操作,分别表示,将wr发布到SQ和RQ中,至于是什么操作(send or write/read),和wr中的opcode有关。

对ibv_post_send()来说,对应的是struct ibv_send_wr,其中有opcode,表示操作码,有SEND/WRITE/READ等。

对于ibv_post_recv()来说,对应的是struct ibv_recv_wr,没有操作码,因为只有接收一个动作,所以不需要定义其它的操作码。但是发送来说,有三类。

在rdma/rdma_verbs.h中,有rdma_post_send(),rdma_post_recv(),rdma_post_read(),rdma_post_write()。

rdma_post_send():把wr发布到QP的SQ中,需要mr

rdma_post_recv():把wr发布到QP的RQ中,需要mr

rdma_post_read():把wr发布到QP的SQ中,执行RDMA READ操作,需要远程地址和rkey,以及本地存储地址和长度,以及mr

rdma_post_write():把wr发布到QP的SQ中,RDMA WRITE操作,需要远程的被写入地址和rkey,以及本地要发送数据的地址和长度,以及mr

所以rdma/rdma_verbs.h中的四种通信函数其实和infiniband/verbs.h中的两种方法是一致的。

ibv_post_send()对应rdma_post_send()、rdma_post_write()

ibv_post_recv()对应rdma_post_recv(),rdma_post_read()

2.2 IB_VERBS

接口以ibv_xx(用户态)或者ib_xx(内核态)作为前缀,是最基础的编程接口,使用IB_VERBS就足够编写RDMA应用了。

比如:

ibv_create_qp() 用于创建QP
ibv_post_send() 用于下发Send WR
ibv_poll_cq() 用于从CQ中轮询CQE


2.3 RDMA_CM

以rdma_为前缀,主要分为两个功能:

1)CMA(Connection Management Abstraction)---- 建连连接管理

在Socket和Verbs API基础上实现的,用于CM建链并交换信息的一组接口。CM建链是在Socket基础上封装为QP实现,从用户的角度来看,是在通过QP交换之后数据交换所需要的QPN,Key等信息。

比如:

rdma_listen()用于监听链路上的CM建链请求。
rdma_connect()用于确认CM连接。
2)CM VERBS                                                        ----收发数据

RDMA_CM也可以用于数据交换 (收发数据),相当于在verbs API上又封装了一套数据交换接口。

比如:

rdma_post_read()可以直接下发RDMA READ操作的WR,而不像ibv_post_send(),需要在参数中指定操作类型为READ。
rdma_post_ud_send()可以直接传入远端QPN,指向远端的AH,本地缓冲区指针等信息触发一次UD SEND操作。
 

传统以太网的用户,基于Socket API来编写应用程序;而RDMA的用户,基于Verbs API来编写应用程序。

RDMA有三种协议IB/iWARP/RoCE,设计Verbs API通过统一接口,让同一份RDMA程序程序可以无视底层的硬件和链路差异运行在不同的环境中。

2.4 常用API介绍

  • device_list ibv_get_device_list()

用户获取可用的RDMA设备列表,会返回一组可用设备的指针。

  • device_context ibv_open_device(device)

打开一个可用的RDMA设备,返回其上下文指针(这个指针会在以后用来对这个设备进行各种操作)。

  • device_attr, errno ibv_query_device(device_context*)

查询一个设备的属性/能力,比如其支持的最大QP,CQ数量等。返回设备的属性结构体指针,以及错误码。

  • pd ibv_alloc_pd(device_context)

申请PD。该函数会返回一个PD的指针。(PD(内存)保护域

  • mr ibv_reg_mr(pd, addr, length, access_flag)

注册MR。用户传入要注册的内存的起始地址和长度,以及这个MR将要从属的PD和它的访问权限(本地读/写,远端读/写等),返回一个MR的指针给用户。

  • cq ibv_create_cq(device_context, cqe_depth, ...)

创建CQ。用户传入CQ的最小深度(驱动实际申请的可能比这个值大),然后该函数返回CQ的指针

  • qp ibv_create_qp(pd, qp_init_attr)

创建QP。用户传入PD和一组属性(包括RQ和SQ绑定到的CQ、QP绑定的SRQ、QP的能力、QP类型等),向用户返回QP的指针

  • errno ibv_modiy_qp(qp, attr, attr_mask)

修改QP。用户传入QP的指针,以及表示要修改的属性的掩码和要修改值。修改的内容可以是QP状态、对端QPN(QP的序号)、QP能力、端口号和重传次数等等。如果失败,该函数会返回错误码。Modify QP最重要的作用是让QP在不同的状态间迁移,完成RST-->INIT-->RTR-->RTS的状态机转移后才具备下发Send WR的能力。也可用来将QP切换到ERROR状态。

  • errno ibv_destroy_qp(qp)

销毁QP。即销毁QP相关的软件资源。其他的资源也都有类似的销毁接口。

  • event_info, errno ibv_get_async_event(device_context)

从事件队列中获取一个异步事件,返回异步事件的信息(事件来源,事件类型等)以及错误码

  • bad_wr, errno ibv_post_send(qp, wr)

向一个QP下发一个Send WR,参数wr是一个结构体,包含了WR的所有信息。包括wr_id、sge数量、操作码(SEND/WRITE/READ等以及更细分的类型)。

WR的结构会根据服务类型和操作类型有所差异,比如RC服务的WRITE和READ操作的WR会包含远端内存地址和R_Key,UD服务类型会包含AH,远端QPN和Q_Key等。

WR经由驱动进一步处理后,会转化成WQE下发给硬件。

出错之后,该接口会返回出错的WR的指针以及错误码。

  • bad_wr, errno ibv_post_recv(qp, wr)

专门用来下发RECV操作WR的接口

  • num, wc ibv_poll_cq(cq, max_num)

从完成队列CQ中轮询CQE,用户需要提前准备好内存来存放WC,并传入可以接收多少个WC。该接口会返回一组WC结构体(其内容包括wr_id,状态,操作码,QPN等信息)以及WC的数量

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值