1

我希望能够在 shell 脚本中捕获 berr-counter 值。我可以通过以下方式查看值 ip -det link show can0

2: can0: <NOARP,ECHO> mtu 16 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
    link/can  promiscuity 0
    can state STOPPED (berr-counter tx 144 rx 128) restart-ms 100
          bitrate 125000 sample-point 0.866
          tq 133 prop-seg 6 phase-seg1 6 phase-seg2 2 sjw 1
          flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1
          clock 30000000

我可以解析这个输出并捕获 tx/rx 错误计数器,但我宁愿直接捕获这些值。所以,我一直在尝试找到访问这些值的位置。我深入研究了https://github.com/shemminger/iproute2的代码,发现这些值ip/iplink_can.c在函数中的打印位置:

static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])

有代码:

if (tb[IFLA_CAN_BERR_COUNTER]) {
    struct can_berr_counter *bc =
        RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);

    fprintf(f, "(berr-counter tx %d rx %d) ", bc->txerr, bc->rxerr);
}

在同一个文件的底部有一个结构:

struct link_util can_link_util = {
    .id     = "can",
    .maxattr    = IFLA_CAN_MAX,
    .parse_opt  = can_parse_opt,
    .print_opt  = can_print_opt,
    .print_xstats   = can_print_xstats,
    .print_help = can_print_help,
};

但是我在任何地方都找不到can_print_opt,或者can_link_util.print_opt被调用,而且我没有找到任何成功筛选struct rtattrrepo 中的所有内容。

我不确定从这里去哪里获取这些值,而不是从ip -det link show can0

4

1 回答 1

3

也许有点晚了,但我正在尝试同样的事情:从用户空间应用程序中访问 CAN 接口状态和错误计数器,而不调用 ip 和解析输出。正如你所做的那样,我探索了 iproute2 的代码,然后阅读了一些关于 netlink 与网络设备交互的文档。主要你要做的就是发送一个 RTM_GETLINK 消息到一个 netlink 套接字,然后解析响应,即一个嵌套的 netlink 属性列表。

我发现这个非常有趣的起点: http: //iijean.blogspot.com/2010/03/howto-get-list-of-network-interfaces-in.html 在这个博客中,完整代码的链接被破坏了,但它是可在此处获得:https ://gist.github.com/cl4u2/5204374 。请注意,除了“手动”执行所有这些操作之外,还可以使用 libnetlink。

基于此,我能够编写一个测试代码 - 快速而肮脏 - 可以满足您的需求。您只需要确定我的ifIndex_变量,即您的 CAN 网络接口的整数索引(可以通过SIOCGIFINDEX您的 socketcan 套接字上的 ioctl 确定)。

printf("Starting rtnetlink stats reading ...\n");
struct sockaddr_nl local;
struct {
    struct nlmsghdr nlh;
    struct ifinfomsg ifinfo;
} request;
struct sockaddr_nl kernel;
struct msghdr rtnl_msg;
struct iovec io;
pid_t pid = getpid();
qint64 rtnetlink_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = pid;
local.nl_groups = 0;
if (bind(rtnetlink_socket, (struct sockaddr *) &local, sizeof(local)) < 0) {
    printf("Binding failed !\n");
    return true;
}
printf("Binding successful.\n");
memset(&rtnl_msg, 0, sizeof(rtnl_msg));
memset(&kernel, 0, sizeof(kernel));
memset(&request, 0, sizeof(request));
kernel.nl_family = AF_NETLINK;
request.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
request.nlh.nlmsg_type = RTM_GETLINK;
request.nlh.nlmsg_flags = NLM_F_REQUEST;    // NLM_F_ROOT|NLM_F_MATCH| were originally specified and return all interfaces.
request.nlh.nlmsg_pid = pid;
request.nlh.nlmsg_seq = 1; // Must be monotonically increasing, but we send only one.
// Interface is specified only with index.
request.ifinfo.ifi_family = AF_PACKET;
request.ifinfo.ifi_index = ifIndex_;
request.ifinfo.ifi_change = 0;
io.iov_base = &request;
io.iov_len = request.nlh.nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
if (sendmsg(rtnetlink_socket, &rtnl_msg, 0) < 0) {
    printf("Sendmsg finished with an error.\n");
    return true;
}
printf("Sendmsg finished successfully.\n");
// Reply reception
int end = 0;
int replyMaxSize = 8192;
char reply[replyMaxSize];
while (!end) {
    int len;
    struct nlmsghdr *msg_ptr;
    struct msghdr rtnl_reply;
    struct iovec io_reply;
    memset(&io_reply, 0, sizeof(io_reply));
    memset(&rtnl_reply, 0, sizeof(rtnl_reply));

    io.iov_base = reply;
    io.iov_len = replyMaxSize;
    rtnl_reply.msg_iov = &io;
    rtnl_reply.msg_iovlen = 1;
    rtnl_reply.msg_name = &kernel;
    rtnl_reply.msg_namelen = sizeof(kernel);
    printf("Waiting for data ...\n");
    len = recvmsg(rtnetlink_socket, &rtnl_reply, 0);
    printf("Received data with length %d.\n", len);
    if (len) {
        for (msg_ptr = (struct nlmsghdr *) reply; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
            switch(msg_ptr->nlmsg_type) {
                case NLMSG_DONE:
                    end++;
                    printf("Received NLMSG_DONE end message.\n");
                    break;
                case RTM_NEWLINK:
                    printf("Received RTM_NEWLINK message with multipart flag : %d.\n", msg_ptr->nlmsg_flags & NLM_F_MULTI);
                    if (!(msg_ptr->nlmsg_flags & NLM_F_MULTI)) { end++; }
                    struct ifinfomsg *iface;
                    struct rtattr *attribute;
                    struct rtattr *subAttr;
                    int msgLen, attrPayloadLen;
                    iface = (struct ifinfomsg*)NLMSG_DATA(msg_ptr);
                    msgLen = msg_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
                    for (attribute = IFLA_RTA(iface); RTA_OK(attribute, msgLen); attribute = RTA_NEXT(attribute, msgLen)) {
                        switch(attribute->rta_type) {
                            case IFLA_IFNAME:
                                printf("Interface %d name : %s\n", iface->ifi_index, (char *) RTA_DATA(attribute));
                                break;
                            case IFLA_LINKINFO:
                                attrPayloadLen = RTA_PAYLOAD(attribute);
                                printf("Found link information. Parsing %d payload bytes ...\n", attrPayloadLen);
                                for (subAttr = (struct rtattr *)RTA_DATA(attribute); RTA_OK(subAttr, attrPayloadLen); subAttr = RTA_NEXT(subAttr, attrPayloadLen)) {
                                    struct rtattr *subSubAttr;
                                    int subAttrPayloadLen = RTA_PAYLOAD(subAttr);
                                    printf("Found sub-attribute. Type : %d, length : %d.\n", subAttr->rta_type, subAttr->rta_len);
                                    switch (subAttr->rta_type) {
                                        case IFLA_INFO_KIND:
                                            printf("\t Link kind : %s.\n", (char *) RTA_DATA(subAttr));
                                            break;
                                        case IFLA_INFO_DATA:
                                            printf("Found link information data. Parsing %d payload bytes ...\n", RTA_PAYLOAD(subAttr));
                                            for (subSubAttr = (struct rtattr *)RTA_DATA(subAttr); RTA_OK(subSubAttr, subAttrPayloadLen); subSubAttr = RTA_NEXT(subSubAttr, subAttrPayloadLen)) {
                                                printf("Found sub-sub-attribute. Type : %d, length : %d.\n", subSubAttr->rta_type, subSubAttr->rta_len);
                                                switch (subSubAttr->rta_type) {
                                                    case IFLA_CAN_STATE:
                                                    {
                                                        int state = *(int *)RTA_DATA(subSubAttr);
                                                        printf("State : %d\n", state);
                                                        break;
                                                    }
                                                    case IFLA_CAN_BERR_COUNTER:
                                                    {
                                                        struct can_berr_counter *bc = (struct can_berr_counter *)RTA_DATA(subSubAttr);
                                                        printf("Error counters : (berr-counter tx %d rx %d)\n", bc->txerr, bc->rxerr);
                                                        break;
                                                    }
                                                    default:
                                                        break;
                                                }
                                            }
                                            break;
                                        case IFLA_INFO_XSTATS:
                                        default:
                                            break;
                                    }
                                }
                                break;
                            default:
                                printf("New attribute. Type : %d, length : %d.\n", attribute->rta_type, attribute->rta_len);
                                break;
                        }
                    }
                    printf("Finished parsing attributes.\n");
                    break;
                case NLMSG_ERROR:
                    printf("Could not read link details for interface %d.\n", ifIndex_);
                    end++;
                    break;
                default:
                    printf("Received unexpected message ID : %d.\n", msg_ptr->nlmsg_type);
                    break;
            }
            printf("Finished parsing message.\n");
        }
        printf("Finished parsing data.\n");
    }
}
close(rtnetlink_socket);
return true;
于 2018-11-20T13:23:14.543 回答