从ip链路显示捕获berr计数器发送/接收

从ip链路显示捕获berr计数器发送/接收,ip,embedded-linux,can-bus,ash,socketcan,Ip,Embedded Linux,Can Bus,Ash,Socketcan,我希望能够在shell脚本中捕获berr计数器值。我可以通过以下方式查看值: ip-det链接显示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

我希望能够在shell脚本中捕获berr计数器值。我可以通过以下方式查看值:
ip-det链接显示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
代码如下:

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\u-print\u-opt
can\u-link\u-util.print\u-opt
的任何地方,而且我还没有找到成功筛选repo中所有
struct-rtar
的地方


除了从
ip-det link show can0

的输出中获取这些值之外,我不确定从这里到哪里获取这些值,可能有点晚了,但我尝试了同样的事情:从用户空间应用程序中访问CAN接口状态和错误计数器,而不调用ip和解析输出。 正如您所做的,我研究了iproute2的代码,然后阅读了一些有关netlink与网络设备交互的文档。主要需要做的是将RTM_GETLINK消息发送到netlink套接字,然后解析响应,即netlink属性的嵌套列表

我发现这个非常有趣的起点: 在此博客中,指向完整代码的链接已断开,但可在此处找到:。 请注意,也可以使用libnetlink,而不是“手动”执行所有这些操作

基于这一点,我能够编写一个测试代码——快速而肮脏——满足您的需求。您只需确定my
ifIndex\uCode>变量,该变量是CAN网络接口的整数索引(可通过socketcan套接字上的
SIOCGIFINDEX
ioctl确定)

printf(“开始读取rtnetlink统计数据…\n”);
结构sockaddr_nl local;
结构{
结构nlmsghdr nlh;
结构IFINFOMG ifinfo;
}请求;
结构sockaddr_nl内核;
结构msghdr rtnl_msg;
结构iovec io;
pid_t pid=getpid();
qint64 rtnetlink\u套接字=套接字(AF\u NETLINK、SOCK\u RAW、NETLINK\u路由);
memset(&local,0,sizeof(local));
local.nl_family=AF_NETLINK;
local.nl_pid=pid;
local.nl_组=0;
if(bind(rtnetlink_socket,(struct sockaddr*)&local,sizeof(local))<0{
printf(“绑定失败!\n”);
返回true;
}
printf(“绑定成功。\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-ifinfo-msg));
request.nlh.nlmsg_type=RTM_GETLINK;
request.nlh.nlmsg_flags=NLM_F_request;//最初指定了NLM_F_ROOT | NLM_F_MATCH |并返回所有接口。
request.nlh.nlmsg_pid=pid;
request.nlh.nlmsg_seq=1;//必须是单调递增的,但我们只发送一个。
//接口仅使用索引指定。
request.ifinfo.ifi_family=AF_数据包;
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(内核);
if(sendmsg(rtnetlink\u socket,&rtnl\u msg,0)<0){
printf(“Sendmsg已完成,但出现错误。\n”);
返回true;
}
printf(“Sendmsg已成功完成。\n”);
//答复接待
int end=0;
int replyMaxSize=8192;
char reply[replyMaxSize];
当(!结束){
内伦;
结构nlmsghdr*msg_ptr;
结构msghdr rtnl_回复;
结构iovec io_回复;
memset(&io_-reply,0,sizeof(io_-reply));
memset(&rtnl_reply,0,sizeof(rtnl_reply));
io.iov_base=回复;
io.iov_len=replyMaxize;
rtnl_reply.msg_iov=&io;
rtnl_reply.msg_iovlen=1;
rtnl_reply.msg_name=&kernel;
rtnl_reply.msg_namelen=sizeof(内核);
printf(“等待数据…\n”);
len=recvmsg(rtnetlink\u套接字和rtnl\u应答,0);
printf(“接收到长度为%d的数据。\n”,len);
如果(len){
对于(msg_ptr=(结构nlmsghdr*)回复;NLMSG_OK(msg_ptr,len);msg_ptr=NLMSG_NEXT(msg_ptr,len)){
开关(msg\U ptr->nlmsg\U类型){
案例NLMSG_完成:
end++;
printf(“收到NLMSG_结束消息。\n”);
打破
案例RTM_NEWLINK:
printf(“接收到带有多部分标志%d的RTM_NEWLINK消息。\n”,msg_ptr->nlmsg_标志和NLM_F_MULTI);
如果(!(msg_ptr->nlmsg_flags&NLM_F_MULTI)){end++}
结构IFINFOMG*iface;
struct rtattr*属性;
结构rtattr*子TTR;
int msgLen,attrPayloadLen;
iface=(结构ifinfomsg*)NLMSG_数据(msg_ptr);
msgLen=msg_ptr->nlmsg_len-nlmsg_长度(sizeof(*iface));
对于(属性=IFLA\U RTA(iface);RTA\U OK(属性,msgLen);属性=RTA\U NEXT(属性,msgLen)){
开关(属性->rta\U类型){
案例IFLA\U IFNAME:
printf(“接口%d名称:%s\n”,iface->ifi_索引,(字符*)RTA_数据(属性));
打破
案例IFLA\U链接信息:
attrPayloadLen=RTA_有效载荷(属性);
printf(“找到链接信息。正在分析%d个有效负载字节…\n”,attrPayloadLen);
对于(subAttr=(struct rtattr*)RTA_数据(属性);RTA_OK(subAttr,attrPayloadLen);subAttr=RTA_NEXT(subAttr,attrPayloadLen)){
结构rtattr*子子子结构rtattr;
int subAttrPayloadLen=RTA_有效载荷(subAttr);
printf(“找到子属性。类型:%d,长度:%d。\n”,子属性->rta\u类型,子属性->rta\u len);
开关(子TTR->rta\U型){
案例IFLA\u信息\u种类:
printf(“\t链接类型:%s.\n”,(字符*)RTA_数据(子TTR)
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,
};
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;