我希望能够在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 berr计数器,但是我宁愿直接捕获这些值。因此,我一直在尝试找到在何处访问这些值。我研究了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 rtattr
的筛选都没有成功。
除了从ip -det link show can0
的输出中获取这些值外,我不确定从何处获取这些值
答案 0 :(得分:0)
也许有点晚了,但是我正在尝试相同的事情:从用户空间应用程序内部访问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网络接口的整数索引(可以由您的socketcan套接字上的SIOCGIFINDEX
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;