使用者空間 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