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