Linux下RDMA驱动程序探索系列-2

news2024/12/30 2:20:22

本系列文章将带领读者逐步了解Linux操作系统下的RDMA子系统。本篇文章作为系列的第二篇,将深入内核态驱动程序的代码,主要介绍如下内容:

  • Driver的初始化流程
  • 几个重要verbs回调函数的简介

01、Kernel Driver的初始化流程

由于不同厂商的驱动程序千差万别,在此不以具体厂商的驱动程序进行介绍,而是以Kernel中核心的API调用为锚点进行介绍。读者在阅读完本篇文章后,可以在自己感兴趣的厂商驱动代码中搜索这些API,从而快速梳理出这些驱动程序的框架。

驱动的加载与激活

作为一个Linux Kernel Driver,其入口点的位置和普通的Driver程序一样,都是通过module_init来指定一个函数作为入口点。

由于基本上所有RDMA网卡都是PCIe设备,因此在驱动程序入口执行后,首先要做的是初始化PCIe设备相关的操作,典型的就是调用pci_register_driver向Kernel注册自己所感兴趣的PCIe设备,提供probe回调函数,这样kernel在匹配到驱动所对应的硬件后,就会调用probe函数。所以,从某种角度上来说,PCIe设备的probe回调函数才是绝大多数RDMA驱动的主入口,因为如果没有硬件插入主板的话,驱动可以处于静默状态,只有检测到PCIe硬件以后,整个驱动才开始活跃起来。(当然,上述流程是针对RDMA硬件设备的驱动而言的,对于一些例外情况,例如Linux在drivers/infiniband/sw目录中提供的rxe驱动等,是通过软件来模拟硬件行为的,不涉及到真实的硬件,则初始化流程必然会有所差异)。

RDMA设备注册

驱动程序的核心部分被激活以后,接下来的操作就主要是在Kernel的RDMA框架下进行工作了。该框架提供了一系列以ib_开头的系统调用,在接下的文章中将介绍为了让操作系统可以识别到一个RDMA设备所需要的最少的ib_API调用。

首先,我们需要调用ib_alloc_device来申请一个用来描述RDMA设备的结构体,一个例子如下:

不出意外的,上述代码中使用了Kernel中经典的通过结构体嵌套和container_of来实现类似“面向对象”风格变成的写法。其中dtld_dev结构体是用来表述一块RDMA网卡的顶层结构,其中必须放入一个ib_device类型的成员,从而使得该结构体可以被Kernel的RDMA框架所识别。这个结构体定义好之后,就可以调用ib_alloc_device来申请一块Kernel中的内存用于存放这个设备的描述符了。

struct dtld_dev {
    struct ib_device ib_dev;
    // Other custom fields
};

struct dtld_dev *dtld = NULL;

dtld = ib_alloc_device(dtld_dev, ib_dev);

拿到设备描述符以后,接下来要调用的是ib_set_device_ops,这个API需要传入一个ib_device_ops类型的结构体,该结构体中定义了RDMA设备可以支持的各种回调函数,一个简单的例子如下所示:

static const struct ib_device_ops dtld_dev_ops = {
    .owner = THIS_MODULE,
    .driver_id = RDMA_DRIVER_UNKNOWN,
    .uverbs_abi_ver = DTLD_UVERBS_ABI_VERSION,
    
    // all kinds of callback functions
    .alloc_ucontext = dtld_alloc_ucontext,
    .get_port_immutable = dtld_port_immutable,
    .query_port = dtld_query_port,
    .query_device = dtld_query_device,
    .dealloc_ucontext = dtld_dealloc_ucontext,
    .get_link_layer = dtld_get_link_layer,
    .mmap = dtld_mmap,
    .mmap_free = dtld_mmap_free
    // a lot more callbacks, not listed here
};

可以看到这个结构体的前三个字段定义了一些元信息,此后的数十个字段都是Kernel中RDMA框架所支持的各种回调函数的挂载点。上述列出的是一些必要的回调函数,有了这些回调函数的支持,上层应用便可以通过API函数查询到一个可用的RDMA设备了(虽然这个设备现在还只是一个空壳子)。具体这些回调函数的作用,将在下一小节中进行介绍。

上述两个API的调用都是正式将RDMA设备注册给操作系统之前的准备工作。打个比方,就像去一些单位线下办理业务,在正式办理之前需要填好各种申请表格,上面第一个API的作用类似于找人要一张申请表(分配一块内存给设备描述符),第二个API的作用相当于把申请表填好(准备好各种回调函数),接下来的这个API是真正办理业务的API了(向操作系统正式注册这个RDMA设备):ib_register_device。

在调用ib_register_device以后,如果上层用户态驱动安装正常,则可以通过rdma link show命令行指令观察到一块可以使用RDMA网卡出现在列表中,说明操作系统已经接受了上面的注册申请。

02、几个重要verbs回调函数的简介

在上面第二步填写申请表的操作中,最重要的就是那些回调函数了,很多用户态的管理类API操作,都会最终调用到这些回调函数上来。接下来我们来看几个重要的回调函数,这些回调函数支撑了用户态的rdma link show命令行指令。

query_device 回调

该回调的主要作用是返回设备的必要信息,原型如下:

static int dtld_query_device(
    struct ib_device *dev, 
    struct ib_device_attr *attr,
    struct ib_udata *uhw);

从原型声明中可以看到,核心是要通过*attr将设备的各种属性信息返回给Kernel的RDMA框架。这个ib_device_attr类型的结构体是一个拥有40多个字段的结构体,其中主要包含了设备所支持的各种极限参数,例如最大的QP数量、最大的MR数量、最大的PD数量等等这些东西。

query_port 回调

这个回调的作用是返回端口的必要信息,原型如下:

static int dtld_query_port(
    struct ib_device *dev, 
    u32 port_num,
    struct ib_port_attr *attr);

从名字就可以看出,这个回调的作用和query_device回调是很类似的,只不过这个要返回端口的属性,而不是设备的属性。其中的ib_port_attr结构体主要包含了端口的速率信息、链路是否通常、MTU配置等,对于一个空壳驱动程序而言,可以通过直接返回如下的属性来让上层应用看到一个可用的接口:

attr->state = IB_PORT_ACTIVE;
attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;

dtld_get_link_layer回调

该函数主要用于返回链路层的类型,例如对于一个RoCE设备,则该回调需要返回IB_LINK_LAYER_ETHERNET

alloc_ucontext回调

这个回调函数会在上层应用打开设备时被调用,可以在这里完成一些对设备使用前的一些初始化工作,例如将下发WQE的环形缓冲区地址映射到用户态等操作,都可以在这个回调中完成。

提到内存地址的映射,由于RDMA的使用过程中需要很多用户态跳过内核直接操作硬件的操作,因此将硬件上的CSR或Buffer映射到用户态是一个常见的操作。RDMA框架也为此提供了一套映射机制。关于这套映射机制的介绍,我们将在后面单独列出一篇文章进行介绍。对于前文中提到的mmap回调函数的使用,我们也将放到这篇文章中一同进行介绍,敬请期待。

往期推荐

1. Linux下RDMA驱动程序探索系列-1

2. 规模弹性:管理谷歌的TPUv4机器学习超级计算机

达坦科技始终致力于打造高性能 Al+ Cloud 基础设施平台,积极推动 AI 应用的落地。达坦科技通过软硬件深度融合的方式,提供高性能存储和高性能网络。为 AI 应用提供弹性、便利、经济的基础设施服务,以此满足不同行业客户对 AI+Cloud 的需求。

公众号:达坦科技DatenLord

DatenLord官网

https://datenlord.github.io/zh-cn/

知乎账号:

达坦科技DatenLord - 知乎

B站

https://space.bilibili.com/2017027518

邮箱:info@datenlord.com

如果您有兴趣加入达坦科技Rust前沿技术交流群或硬件相关的群 ,请添加小助手微信:DatenLord_Tech

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1948267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进销存系统开发,含税小计和含税单价计算,含税和不含税,1000元电脑为案例

if (data ! null) {console.log("中断调试,2024-7-25 最终计算税务");//删除不需要会报错var 未来之窗_人工智能_计算_税额 parseFloat((data.price * data.num * data.tax_rate / 100 ).toFixed(2));var 未来之窗_人工智能_计算_含税小计 parseFloat((…

js轮播图制作

实现一个简单的JavaScript轮播图可以通过以下步骤完成: 创建HTML结构,包括轮播图容器和图片列表。 使用CSS进行样式设置,包括隐藏多余的图片。 使用JavaScript编写函数来控制图片的切换。

07-15 周一 lmdeploy导出迁移因子到量化模型中

07-15 周一 lmdeploy导出迁移因子到量化模型中 时间版本修改人描述2024年7月15日14:57:02V0.1宋全恒新建文档 简介 方案设计 由于norm层的前后导致smoothquant执行量化不好融合,为了降低我事先的难度,所以就不再融合normalization的算子了&#xff0c…

vue3编程-import.meta.glob实现动态路由(菜单)

import.meta.glob 是vite提供的批量懒加载组件的方法 本地开发环境: const modules import.meta.glob(../views/**/*.vue)这段代码返回的modules是一个Map: key是vue文件的相对路径,值是一个函数,将函数打印出来,如…

【微信小程序实战教程】之微信小程序原生开发详解

微信小程序原生开发详解 微信小程序的更新迭代非常频繁,几乎每个月都会有新版本发布,这就会让初学者感觉到学习的压力和难度。其实,我们小程序的每次版本迭代都是在现有小程序架构基础之上进行更新的,如果想要学好小程序开发技术&…

配置mysql8.0.21版本docker-compose启动容器

1. 总览 2 docker-compose.xml配置 version: 3 services:mysql:image: 192.168.188.131:8000/mysqlrestart: alwaysvolumes:- ./data:/var/lib/mysql- ./my.cnf:/etc/mysql/my.cnf- ./mysql-files:/var/lib/mysql-files- ./log/mysql:/var/log/mysqlenvironment:MYSQL_ROOT_PA…

Shell实现服务自动部署

一、环境 注意: nfs.example.com应该为nfs.exam.com 172.25.250.101-172.25.250.105 共 5 个 IP 地址由servera.exam.com服务器进行提供。 172.25.250.106 由 serverb.exam.com 服务器进行提供。 二、需求 项目需求: 1. 172.25.250.101 主机上的 W…

UEFI DebugLib 介绍

1.我们调试中常用Debug 打印信息,这些会输出到BIOS串口日志中 EFI_STATUSEFIAPIHelloWorld2(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE *SystemTable){EFI_STATUS Status;StatusEFI_SUCCESS;gST->ConOut->OutputString(gST->ConOut,L&q…

如何保护您的 WordPress 不被黑?

明月可以说是见到过太多 WordPress 网站被黑的示例了,加上平时明月也会接一些 WordPress 疑难杂症的解决服务订单,所以这方面绝对是专业对口了。作为一个资深 WordPress 博客站长,谁都有被黑过的经历,都是一步步走过来的&#xff…

从零入门AI for Science(AI+化学)#Datawhale AI 夏令营

基于天池平台“第二届世界科学智能大赛 物质科学赛道:催化反应产率预测”使用平台 我的Notebook 魔搭社区 https://modelscope.cn/my/mynotebook/preset 赛事官网 上海科学智能研究院 http://competition.sais.com.cn/competitionDetail/532233/myScore Task1 …

七、SpringBoot日志

1. 得到日志对象 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; //打印日志…

【Vue实战教程】之Vue工程化项目详解

Vue工程化项目 随着多年的发展,前端越来越模块化、组件化、工程化,这是前端发展的大趋势。webpack是目前用于构建前端工程化项目的主流工具之一,也正变得越来越重要。本章节我们来详细讲解一下如何使用webpack搭建Vue工程化项目。 1 使用we…

Web渗透-WAF绕过技巧

一、WAF简介 Web应用防护系统(也称为:网站应用级入侵防御系统。英文:Web Application Firewall,简称: WAF)。利用国际上公认的一种说法:Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略…

叮!2024 龙蜥操作系统大会议题征集正式启动

定啦!2024 龙蜥操作系统大会(OpenAnolis Conference,以下简称“龙蜥大会”)将于 2024 年 8 月 30 日在北京中关村国家自主创新示范区会议中心盛大召开。 2024 龙蜥大会由中关村科学城管委会、海淀区委网信办、中国开源软件推进联…

配置sublime的中的C++编译器(.sublime-build),实现C++20

GCC 4.8: 支持 C11 (部分) GCC 4.9: 支持 C11 和 C14 (部分) GCC 5: 完全支持 C14 GCC 6: 支持 C14 和 C17 (部分) GCC 7: 支持 C17 (大部分) GCC 8: 完全支持 C17,部分支持 C20 GCC 9: 支持更多的 C20 特性 GCC 10: 支持大部分 C20 特性 GCC 11: 更全面地支持 C20 …

uniapp开发精选短视频视频小程序实战笔记20240725,实现顶部轮播图和热门短剧

创建项目 创建项目,叫video_app。 在pages.json里面修改一下标题: 新建search搜索页面和me我的页面。 此时界面预览效果如下: 引入静态资源 主要是static里面的内容,全部复制过来。 配置底部导航栏 pages.json,放到顶层,和全部样式同级: "tabBar&quo…

Java的类加载机制

Java的类加载机制是指将类的字节码文件(.class文件)加载到JVM中并将其转换为Class对象的过程。这个过程由类加载器(ClassLoader)完成。Java的类加载机制具有动态性和灵活性,使得Java能够支持动态加载类、实现模块化开发…

4s店客户管理系统小程序的设计

管理员账户功能包括:系统首页,个人中心,用户管理,门店管理,车展管理,汽车品牌管理,新闻头条管理,预约试驾管理,我的收藏管理,系统管理 微信端账号功能包括&a…

HTTP请求入参类型解读

HTTP请求入参类型解读 Content-Type 在HTTP请求中,Content-Type请求头用于指示资源的MIME类型,即请求体的媒体类型。它告诉服务器实际发送的数据类型是什么,以便服务器能够正确地解析和处理这些数据。Content-Type可以有多种值,…

13.2 MongoDB

13.2 MongoDB 1. 概述2. docker安装3. SpringBoot整合MongoDB3.1 依赖3.2 配置连接1. 基于`yml`配置2. 基于配置类配置3.3 启动项坑1坑23.4 新增业务1. 实体类映射2. 数据层3. 业务层4. 控制层5. 测试结果3.5 单条记录查询业务1. 数据层2. 业务层3. 控制层4. 断点测试3.6 分页查…