IPMI 实用小代码,发送 Get Device ID

1. Get Device ID 是什么?

  • 它是我们在 IPMI 里面常用到的一个命令。 它的NetFn 是 0x06 CMD 是 0x01, 在IPMI 世界里,我们常用它来判断BMC工作是否正常。 下面这段代码就演示了我们如何来发送Get Device ID

    2. Get Device ID 实现的大概流程

  • 打开 ipmi 设备 (设备是由ipmi驱动所建立,是一个char设备)
  • 生成需要发送的ipmi信息
  • 通过ioctl发送信息 (ioctl 的实现是通过ipmi驱动提供)
  • 通过ioctl读取返回信息 (ioctl 的实现是通过ipmi驱动提供)
  • 打印输出

    3. 具体的代码实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    #include <stdio.h>
    #include <strings.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <linux/ipmi.h>
    #include <linux/ipmi_msgdefs.h>
    #include<sys/ioctl.h>

    char *devnode = "/dev/ipmi0";

    int main(int argc, char *argv[])

    {
    int i, fd, ret = 0;
    unsigned char data[1024];
    struct ipmi_req req;
    struct ipmi_recv recv;
    struct ipmi_system_interface_addr addr, addr1;

    /* open the ipmi device */
    if ((fd = open(devnode, O_RDWR)) < 0){
    fprintf(stderr, "Can't open ipmi device: %s\n", devnode);
    exit (1);
    };

    /* format required stuff*/
    addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
    addr.channel = IPMI_BMC_CHANNEL;
    addr.lun = 0;
    req.addr = (unsigned char *)&addr;
    req.addr_len = sizeof (addr);

    req.msg.netfn = IPMI_NETFN_APP_REQUEST;
    req.msg.cmd = IPMI_GET_DEVICE_ID_CMD;
    req.msg.data_len = 0;
    req.msg.data = NULL;

    req.msgid++;

    /* use ioctl to send command*/
    ret = ioctl(fd, IPMICTL_SEND_COMMAND, (char *)&req);

    if (ret != 0){
    perror("Error in ioctl IPMICTL_SEND_COMMAND: ");
    }
    printf("Please standby for 3 seconds \n");
    sleep (3);

    /* receive the command response */
    recv.msg.data = data;
    recv.msg.data_len = sizeof (data);
    recv.addr = (unsigned char *)&addr1;
    recv.addr_len = sizeof (addr1);
    ret = ioctl(fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv);

    if (ret != 0) {
    perror("Error in ioctl IPMICTL_RECEIVE_MSG_TRUNC: ");
    } else {
    /*
    * Print the packet
    */
    printf("Packet:\t\trecv_type = %d; msgid = %d\n",
    recv.recv_type, recv.msgid);

    printf("Address:\t");
    printf("addr_type=0x%x", addr1.addr_type);
    printf("; channel=0x%x", (int)addr1.channel);
    printf("; lun=0x%x", (int)addr1.lun);
    printf("\n");

    printf("Msg:\t\t");
    printf("netfn=0x%x", recv.msg.netfn);
    printf("; cmd=0x%x", recv.msg.cmd);
    printf("; data_len=%d", recv.msg.data_len);
    printf("\n");

    printf("Data:\t\t");
    for (i = 0; i < recv.msg.data_len; i++)
    printf("%x, ", (int)recv.msg.data[i]);
    printf("\n");
    }

    close(fd);
    return(0);
    }

    4. 编译后执行

  • 编译
    1
    (samBuildServer1)# gcc -g ipmi_getDeviceID.c -o ipmiGetDeviceID
  • 运行
    1
    2
    3
    4
    5
    6
    (samTestServer1) # ./ipmiGetDeviceID
    Please standby for 3 seconds
    Packet: recv_type = 1; msgid = 2
    Address: addr_type=0xc; channel=0xf; lun=0x0
    Msg: netfn=0x7; cmd=0x1; data_len=16
    Data: 0, 20, 81, 2, a, 2, df, a2, 2, 0, 0, 1, 0, 31, a, a,

    如需了解更多,我们可以参考 IPMI 规范