3. 查询端口属性
任务目标
编写一个命令行工具,通过 InfiniBand 内核接口查询指定设备端口的属性,包括端口状态(Port State)、物理状态(Physical State)、链路宽度(Active Width)和速率(Active Speed),并输出可读结果。
环境依赖
需要 Linux 系统且已安装 InfiniBand 驱动(内核模块 ib_uverbs、ib_core)。编译依赖 libibverbs-dev 和 libibmad-dev(后者用于获取端口状态映射表)。
sudo apt install libibverbs-dev libibmad-dev
关键完整代码
/* port_query.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <infiniband/verbs.h>
#include <infiniband/mad.h>
static const char *port_state_str(enum ibv_port_state st) {
switch (st) {
case IBV_PORT_NOP: return "NOP";
case IBV_PORT_DOWN: return "DOWN";
case IBV_PORT_INIT: return "INIT";
case IBV_PORT_ARMED: return "ARMED";
case IBV_PORT_ACTIVE: return "ACTIVE";
default: return "UNKNOWN";
}
}
static const char *phys_state_str(enum ibv_port_phys_state st) {
switch (st) {
case IBV_PHYS_STATE_SLEEP: return "SLEEP";
case IBV_PHYS_STATE_POLLING: return "POLLING";
case IBV_PHYS_STATE_DISABLED: return "DISABLED";
case IBV_PHYS_STATE_PORT_CONFIGURATION_TRAINING: return "CFG_TRAIN";
case IBV_PHYS_STATE_LINK_UP: return "LINK_UP";
case IBV_PHYS_STATE_LINK_ERROR_RECOVERY: return "LINK_ERR_RECOVERY";
case IBV_PHYS_STATE_PHY_TEST: return "PHY_TEST";
default: return "UNKNOWN";
}
}
int main(int argc, char *argv[]) {
struct ibv_device **dev_list;
struct ibv_context *ctx = NULL;
struct ibv_port_attr attr;
struct ibv_device_attr dev_attr;
int port_num = 1;
int i;
if (argc > 1) port_num = atoi(argv[1]);
dev_list = ibv_get_device_list(NULL);
if (!dev_list) {
perror("ibv_get_device_list");
return 1;
}
for (i = 0; dev_list[i]; ++i) {
ctx = ibv_open_device(dev_list[i]);
if (!ctx) continue;
if (ibv_query_device(ctx, &dev_attr)) {
ibv_close_device(ctx);
ctx = NULL;
continue;
}
if (port_num >= 1 && port_num <= dev_attr.phys_port_cnt) {
if (!ibv_query_port(ctx, port_num, &attr)) {
printf("Device: %s\n", ibv_get_device_name(dev_list[i]));
printf("Port: %d\n", port_num);
printf("State: %s (%d)\n", port_state_str(attr.state), attr.state);
printf("Phys: %s (%d)\n", phys_state_str(attr.phys_state), attr.phys_state);
printf("Width: %dX\n", attr.active_width);
printf("Speed: %s\n", ibv_width_to_rate(attr.active_width, attr.active_speed));
ibv_close_device(ctx);
ibv_free_device_list(dev_list);
return 0;
}
}
ibv_close_device(ctx);
ctx = NULL;
}
fprintf(stderr, "No usable IB device found for port %d\n", port_num);
ibv_free_device_list(dev_list);
return 1;
}
编译与运行
gcc -o port_query port_query.c -libverbs -libmad
# 查询默认端口(端口1)
./port_query
# 查询指定端口(如端口2)
./port_query 2
验证方法
运行程序后,观察输出中的 State 字段。若 InfiniBand 链路已建立,应显示 ACTIVE (4);若未连接或链路断开,则显示 DOWN (2) 或其他非 ACTIVE 状态。物理状态 Phys 在链路正常时应为 LINK_UP (5)。宽度和速率应与实际链路配置一致(例如 Width: 4X、Speed: 40 Gb/sec (4X QDR))。
可通过 ibstat 命令交叉验证:
ibstat | grep -A 8 "Port 1"
对比 ibstat 输出的 State、Physical State、Active Width 和 Active Speed 字段,应与本程序输出一致。
预期输出示例
Device: mlx5_0
Port: 1
State: ACTIVE (4)
Phys: LINK_UP (5)
Width: 4X
Speed: 40 Gb/sec (4X QDR)
以上为基于代码逻辑的预期输出格式,实际数值取决于运行环境的链路配置。