英语

用户空间 MAD 访问

设备文件

每个 InfiniBand 设备的每个端口都有一个附加的 “umad” 设备和一个 “issm” 设备。例如,一个双端口 HCA 将有两个 umad 设备和两个 issm 设备,而一个交换机将为每种类型有一个设备(用于交换机端口 0)。

创建 MAD 代理

可以通过填写一个 struct ib_user_mad_reg_req 结构体,然后在相应设备文件的文件描述符上调用 IB_USER_MAD_REGISTER_AGENT ioctl 来创建一个 MAD 代理。如果注册请求成功,则结构体中将返回一个 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 的使用(见下文)。

接收 MAD

MAD 使用 read() 接收。接收端现在支持 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 内容外,其他 struct ib_user_mad 字段将填充接收到的 MAD 的信息。例如,远程 LID 将在 mad.lid 中。

如果发送超时,将生成一个接收,其中 mad.status 设置为 ETIMEDOUT。否则,当成功接收到 MAD 时,mad.status 将为 0。

可以使用 poll()/select() 等待直到可以读取 MAD。

发送 MAD

MAD 使用 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");

事务 ID

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,默认情况下将使用 struct 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