Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,115 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/core_locking.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_core_locking:
==================
infiniband中间层锁
==================
本指南试图明确infiniband中间层的锁假设。它描述了对位于中间层以下的低
级驱动程序和使用中间层的上层协议的要求。
睡眠和中断环境
==============
除了以下异常情况,ib_device结构体中所有方法的低级驱动实现都可以睡眠。
这些异常情况是列表中的任意的方法:
- create_ah
- modify_ah
- query_ah
- destroy_ah
- post_send
- post_recv
- poll_cq
- req_notify_cq
他们可能不可以睡眠,而且必须可以从任何上下文中调用。
向上层协议使用者输出的相应函数:
- rdma_create_ah
- rdma_modify_ah
- rdma_query_ah
- rdma_destroy_ah
- ib_post_send
- ib_post_recv
- ib_req_notify_cq
因此,在任何情况下都可以安全调用(它们)。
此外,该函数
- ib_dispatch_event
被底层驱动用来通过中间层调度异步事件的“A”,也可以从任何上下文中安全调
用。
可重入性
--------
由低级驱动程序导出的ib_device结构体中的所有方法必须是完全可重入的。
即使使用同一对象的多个函数调用被同时运行,低级驱动程序也需要执行所有
必要的同步以保持一致性。
IB中间层不执行任何函数调用的序列化。
因为低级驱动程序是可重入的,所以不要求上层协议使用者任何顺序执行。然
而,为了得到合理的结果,可能需要一些顺序。例如,一个使用者可以在多个
CPU上同时安全地调用ib_poll_cq()。然而,不同的ib_poll_cq()调用之间
的工作完成信息的顺序没有被定义。
回调
----
低级驱动程序不得直接从与ib_device方法调用相同的调用链中执行回调。例
如,低级驱动程序不允许从post_send方法直接调用使用者的完成事件处理程
序。相反,低级驱动程序应该推迟这个回调,例如,调度一个tasklet来执行
这个回调。
低层驱动负责确保同一CQ的多个完成事件处理程序不被同时调用。驱动程序必
须保证一个给定的CQ的事件处理程序在同一时间只有一个在运行。换句话说,
以下情况是不允许的::
CPU1 CPU2
low-level driver ->
consumer CQ event callback:
/* ... */
ib_req_notify_cq(cq, ...);
low-level driver ->
/* ... */ consumer CQ event callback:
/* ... */
return from CQ event handler
完成事件和异步事件回调的运行环境没有被定义。 根据低级别的驱动程序,它可能是
进程上下文、softirq上下文或中断上下文。上层协议使用者可能不会在回调中睡眠。
热插拔
------
当一个低级驱动程序调用ib_register_device()时,它宣布一个设备已经
准备好供使用者使用,所有的初始化必须在这个调用之前完成。设备必须保
持可用,直到驱动对ib_unregister_device()的调用返回。
低级驱动程序必须从进程上下文调用ib_register_device()和
ib_unregister_device()。如果使用者在这些调用中回调到驱动程序,它
不能持有任何可能导致死锁的semaphores。
一旦其结构体ib_client的add方法被调用,上层协议使用者就可以开始使用
一个IB设备。使用者必须在从移除方法返回之前完成所有的清理工作并释放
与设备相关的所有资源。
使用者被允许在其添加和删除方法中睡眠。
@@ -0,0 +1,39 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/index.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_index:
==========
infiniband
==========
.. toctree::
:maxdepth: 1
core_locking
ipoib
sysfs
tag_matching
user_mad
user_verbs
.. only:: subproject and html
Indices
=======
* :ref:`genindex`
@@ -0,0 +1,111 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/ipoib.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_ipoib:
=========================
infiniband上的IP(IPoIB)
=========================
ib_ipoib驱动是IETF ipoib工作组发布的RFC 4391和4392所规定的
infiniband上IP协议的一个实现。它是一个“本地”实现,即把接口类型设置为
ARPHRD_INFINIBAND,硬件地址长度为20(早期的专有实现向内核伪装为以太网
接口)。
分区和P_Keys
============
当IPoIB驱动被加载时,它会使用索引为0的P_Key给每个端口创建一个接口。要用
不同的P_Key创建一个接口,将所需的P_Key写入主接口的
/sys/class/net/<intf name>/create_child文件里面。比如说::
echo 0x8001 > /sys/class/net/ib0/create_child
这将用P_Key 0x8001创建一个名为ib0.8001的接口。要删除一个子接口,使用
``delete_child`` 文件::
echo 0x8001 > /sys/class/net/ib0/delete_child
任何接口的P_Key都由“pkey”文件给出,而子接口的主接口在“parent”中。
子接口的创建/删除也可以使用IPoIB的rtnl_link_ops来完成,使用两种
方式创建的子接口的行为是一样的。
数据报与连接模式
================
IPoIB驱动支持两种操作模式:数据报和连接。模式是通过接口的
/sys/class/net/<intf name>/mode文件设置和读取的。
在数据报模式下,使用IB UD(不可靠数据报)传输,因此接口MTU等于IB L2 MTU
减去IPoIB封装头(4字节)。例如,在一个典型的具有2K MTU的IB结构中,IPoIB
MTU将是2048 - 4 = 2044字节。
在连接模式下,使用IB RC(可靠的连接)传输。连接模式利用IB传输的连接特性,
允许MTU达到最大的IP包大小64K,这减少了处理大型UDP数据包、TCP段等所需的
IP包数量,提高了大型信息的性能。
在连接模式下,接口的UD QP仍被用于组播和与不支持连接模式的对等体的通信。
在这种情况下,ICMP PMTU数据包的RX仿真被用来使网络堆栈对这些邻居使用较
小的UD MTU。
无状态卸载
==========
如果IB HW支持IPoIB无状态卸载,IPoIB会向网络堆栈广播TCP/IP校验和/或大量
传送(LSO)负载转移能力。
大量传送(LSO)负载转移也已实现,可以使用ethtool调用打开/关闭。目前,LRO
只支持具有校验和卸载能力的设备。
无状态卸载只在数据报模式下支持。
中断管理
========
如果底层IB设备支持CQ事件管理,可以使用ethtool来设置中断缓解参数,从而减少
处理中断产生的开销。IPoIB的主要代码路径不使用TX完成信号的事件,所以只支持
RX管理。
调试信息
========
通过将CONFIG_INFINIBAND_IPOIB_DEBUG设置为“y”来编译IPoIB驱动,跟踪信
息被编译到驱动中。通过将模块参数debug_level和mcast_debug_level设置为1来
打开它们。这些参数可以在运行时通过/sys/module/ib_ipoib/的文件来控制。
CONFIG_INFINIBAND_IPOIB_DEBUG也启用debugfs虚拟文件系统中的文件。通过挂
载这个文件系统,例如用::
mount -t debugfs none /sys/kernel/debug
可以从/sys/kernel/debug/ipoib/ib0_mcg等文件中获得关于多播组的统计数据。
这个选项对性能的影响可以忽略不计,所以在正常运行时,在debug_level设置为
0的情况下启用这个选项是安全的。
CONFIG_INFINIBAND_IPOIB_DEBUG_DATA当data_debug_level设置为1时,可以
在数据路径中启用更多的调试输出。 然而,即使禁用输出,启用这个配置选项也
会影响性能,因为它在快速路径中增加了测试。
引用
====
在InfiniBand上传输IP(IPoIB)(RFC 4391)。
http://ietf.org/rfc/rfc4391.txt
infiniband上的IP:上的IP架构(RFC 4392)。
http://ietf.org/rfc/rfc4392.txt
infiniband上的IP: 连接模式 (RFC 4755)
http://ietf.org/rfc/rfc4755.txt
@@ -0,0 +1,21 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/sysfs.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_sysfs:
=========
Sysfs文件
=========
sysfs接口已移至
Documentation/ABI/stable/sysfs-class-infiniband.
@@ -0,0 +1,63 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/tag_matching.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_tag_matching:
============
标签匹配逻辑
============
MPI标准定义了一套规则,称为标签匹配,用于将源发送操作与目的接收匹配。以下参数必
须与以下源和目的参数相匹配:
* 沟通者
* 用户标签--通配符(wild card)可由接收方指定
* 来源等级--通配符可由接收方指定
* 目的地等级 – wild
排序规则要求,当一对以上的发送和接收消息信封可能匹配时,包括最早发布-发送和最早
发布-接收的一对是必须用来满足匹配操作的一对。然而,这并不意味着标签是按照它们被
创建的顺序消耗的,例如,如果早期的标签不能用来满足匹配规则,那么后来生成的标签
可能被消耗。
当消息从发送方发送到接收方时,通信库可能试图在相应的匹配接收被发布之后或之前处
理该操作。如果匹配的接收被发布,这就是一个预期的消息,否则就被称为一个意外的消
息。实现时经常为这两种不同的匹配实例使用不同的匹配方案。
为了减少MPI库的内存占用,MPI实现通常使用两种不同的协议来实现这一目的:
1. Eager协议--当发送方处理完发送时,完整的信息就会被发送。在send_cq中会收到
一个完成发送的通知,通知缓冲区可以被重新使用。
2. Rendezvous协议--发送方在第一次通知接收方时发送标签匹配头,也许还有一部分
数据。当相应的缓冲区被发布时,响应者将使用头中的信息,直接向匹配的缓冲区发起
RDMA读取操作。为了使缓冲区得到重用,需要收到一个fin消息。
标签匹配的实现
==============
使用的匹配对象有两种类型,即发布的接收列表和意外消息列表。应用程序通过调用发布
的接收列表中的MPI接收例程发布接收缓冲区,并使用MPI发送例程发布发送消息。发布的
接收列表的头部可以由硬件来维护,而软件则要对这个列表进行跟踪。
当发送开始并到达接收端时,如果没有为这个到达的消息预先发布接收,它将被传递给软
件并被放在意外(unexpect)消息列表中。否则,将对该匹配进行处理,包括交会处理,
如果合适的话,将数据传送到指定的接收缓冲区。这允许接收方MPI标签匹配与计算重叠。
当一个接收信息被发布时,通信库将首先检查软件的意外信息列表,以寻找一个匹配的接
收信息。如果找到一个匹配的,数据就会被送到用户缓冲区,使用一个软件控制的协议。
UCX的实现根据数据大小,使用急切或交会协议。如果没有找到匹配,整个预置的接收列
表由硬件维护,并且有空间在这个列表中增加一个预置的接收,这个接收被传递给硬件。
软件要对这个列表进行跟踪,以帮助处理MPI取消操作。此外,由于硬件和软件在标签匹
配操作方面预计不会紧密同步,这个影子列表被用来检测预先发布的接收被传递到硬件的
情况,因为匹配的意外消息正在从硬件传递到软件。
@@ -0,0 +1,164 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/user_mad.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_user_mad:
===============
用户空间MAD访问
===============
设备文件
========
每个InfiniBand设备的每个端口都有一个“umad”设备和一个“issm”设备连接。
例如,一个双端口的HCA将有两个umad设备和两个issm设备,而一个交换机将
有每个类型的一个设备(对于交换机端口0)。
创建MAD代理
===========
一个MAD代理可以通过填写一个结构体ib_user_mad_reg_req来创建,然后在
适当的设备文件的文件描述符上调用IB_USER_MAD_REGISTER_AGENT ioctl。
如果注册请求成功,结构体中会返回一个32位的ID。比如说::
struct ib_user_mad_reg_req req = { /* ... */ };
ret = ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (char *) &req);
if (!ret)
my_agent = req.id;
else
perror("agent register");
代理可以通过IB_USER_MAD_UNREGISTER_AGENT ioctl取消注册。另外,所有
通过文件描述符注册的代理在描述符关闭时将被取消注册。
2014
现在提供了一个新的注册IOctl,允许在注册时提供额外的字段。这个注册
调用的用户隐含了对pkey_index的使用(见下文)。现在提供了一个新的
注册IOctl,允许在注册时提供额外的字段。这个注册调用的用户隐含了对
pkey_index的使用(见下文)。
接收MADs
========
使用read()接收MAD。现在接收端支持RMPP。传给read()的缓冲区必须至少是
一个struct ib_user_mad + 256字节。比如说:
如果传递的缓冲区不足以容纳收到的MAD(RMPP),errno被设置为ENOSPC,需
要的缓冲区长度被设置在mad.length中。
正常MAD(非RMPP)的读取示例::
struct ib_user_mad *mad;
mad = malloc(sizeof *mad + 256);
ret = read(fd, mad, sizeof *mad + 256);
if (ret != sizeof mad + 256) {
perror("read");
free(mad);
}
RMPP读取示例::
struct ib_user_mad *mad;
mad = malloc(sizeof *mad + 256);
ret = read(fd, mad, sizeof *mad + 256);
if (ret == -ENOSPC)) {
length = mad.length;
free(mad);
mad = malloc(sizeof *mad + length);
ret = read(fd, mad, sizeof *mad + length);
}
if (ret < 0) {
perror("read");
free(mad);
}
除了实际的MAD内容外,其他结构体ib_user_mad字段将被填入收到的MAD的信
息。例如,远程LID将在mad.lid中。
如果发送超时,将产生一个接收,mad.status设置为ETIMEDOUT。否则,当一个
MAD被成功接收后,mad.status将是0。
poll()/select()可以用来等待一个MAD可以被读取。
poll()/select()可以用来等待,直到可以读取一个MAD。
发送MADs
========
MADs是用write()发送的。发送的代理ID应该填入MAD的id字段,目的地LID应该
填入lid字段,以此类推。发送端确实支持RMPP,所以可以发送任意长度的MAD。
比如说::
struct ib_user_mad *mad;
mad = malloc(sizeof *mad + mad_length);
/* fill in mad->data */
mad->hdr.id = my_agent; /* req.id from agent registration */
mad->hdr.lid = my_dest; /* in network byte order... */
/* etc. */
ret = write(fd, &mad, sizeof *mad + mad_length);
if (ret != sizeof *mad + mad_length)
perror("write");
交换IDs
=======
umad设备的用户可以在发送的MAD中使用交换ID字段的低32位(也就是网络字节顺序中
最小有效的一半字段)来匹配请求/响应对。上面的32位是保留给内核使用的,在发送
MAD之前会被改写。
P_Key索引处理
=============
旧的ib_umad接口不允许为发送的MAD设置P_Key索引,也没有提供获取接收的MAD的
P_Key索引的方法。一个带有pkey_index成员的struct ib_user_mad_hdr的新布局已
经被定义;然而,为了保持与旧的应用程序的二进制兼容性,除非在文件描述符被用于
其他用途之前调用IB_USER_MAD_ENABLE_PKEY或IB_USER_MAD_REGISTER_AGENT2 ioctl
之一,否则不会使用这种新布局。
在2008年9月,IB_USER_MAD_ABI_VERSION将被增加到6,默认使用新的ib_user_mad_hdr
结构布局,并且IB_USER_MAD_ENABLE_PKEY ioctl将被删除。
设置IsSM功能位
==============
要为一个端口设置IsSM功能位,只需打开相应的issm设备文件。如果IsSM位已经被设置,那
么打开调用将阻塞,直到该位被清除(或者如果O_NONBLOCK标志被传递给open(),则立即返
回,errno设置为EAGAIN)。当issm文件被关闭时,IsSM位将被清除。在issm文件上不能进
行任何读、写或其他操作。
/dev文件
========
为了用 udev自动创建相应的字符设备文件,一个类似::
KERNEL=="umad*", NAME="infiniband/%k"
KERNEL=="issm*", NAME="infiniband/%k"
的规则可以被使用。它将创建节点的名字::
/dev/infiniband/umad0
/dev/infiniband/issm0
为第一个端口,以此类推。与这些设备相关的infiniband设备和端口可以从以下文件中确定::
/sys/class/infiniband_mad/umad0/ibdev
/sys/class/infiniband_mad/umad0/port
和::
/sys/class/infiniband_mad/issm0/ibdev
/sys/class/infiniband_mad/issm0/port
@@ -0,0 +1,72 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/infiniband/user_verbs.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
王普宇 Puyu Wang <realpuyuwang@gmail.com>
时奎亮 Alex Shi <alexs@kernel.org>
.. _cn_infiniband_user_verbs:
=================
用户空间verbs访问
=================
ib_uverbs模块,通过启用CONFIG_INFINIBAND_USER_ACCESS构建,使用户空间
通过“verbs”直接访问IB硬件,如InfiniBand架构规范第11章所述。
要使用verbs,需要libibverbs库,可从https://github.com/linux-rdma/rdma-core。
libibverbs包含一个独立于设备的API,用于使用ib_uverbs接口。libibverbs
还需要为你的InfiniBand硬件提供适当的独立于设备的内核和用户空间驱动。例如,
要使用Mellanox HCA,你需要安装ib_mthca内核模块和libmthca用户空间驱动。
用户-内核通信
=============
用户空间通过/dev/infiniband/uverbsN字符设备与内核进行慢速路径、资源管理
操作的通信。快速路径操作通常是通过直接写入硬件寄存器mmap()到用户空间来完成
的,没有系统调用或上下文切换到内核。
命令是通过在这些设备文件上的write()s发送给内核的。ABI在
drivers/infiniband/include/ib_user_verbs.h中定义。需要内核响应的命令的结
构包含一个64位字段,用来传递一个指向输出缓冲区的指针。状态作为write()系统调
用的返回值被返回到用户空间。
资源管理
========
由于所有IB资源的创建和销毁都是通过文件描述符传递的命令完成的,所以内核可以跟
踪那些被附加到给定用户空间上下文的资源。ib_uverbs模块维护着idr表,用来在
内核指针和不透明的用户空间句柄之间进行转换,这样内核指针就不会暴露给用户空间,
而用户空间也无法欺骗内核去跟踪一个假的指针。
这也允许内核在一个进程退出时进行清理,并防止一个进程触及另一个进程的资源。
内存固定
========
直接的用户空间I/O要求与作为潜在I/O目标的内存区域保持在同一物理地址上。ib_uverbs
模块通过get_user_pages()和put_page()调用来管理内存区域的固定和解除固定。它还核
算进程的pinned_vm中被固定的内存量,并检查非特权进程是否超过其RLIMIT_MEMLOCK限制。
被多次固定的页面在每次被固定时都会被计数,所以pinned_vm的值可能会高估一个进程所
固定的页面数量。
/dev文件
========
要想用udev自动创建适当的字符设备文件,可以采用如下规则::
KERNEL=="uverbs*", NAME="infiniband/%k"
可以使用。 这将创建设备节点,名为::
/dev/infiniband/uverbs0
等等。由于InfiniBand的用户空间verbs对于非特权进程来说应该是安全的,因此在udev规
则中加入适当的MODE或GROUP可能是有用的。