用户空间 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