diff --git a/include/netlink/route/link/can.h b/include/netlink/route/link/can.h index 7df50e3d..1c23660a 100644 --- a/include/netlink/route/link/can.h +++ b/include/netlink/route/link/can.h @@ -60,6 +60,9 @@ extern int rtnl_link_can_get_data_bittiming(struct rtnl_link *, extern int rtnl_link_can_set_data_bittiming(struct rtnl_link *, const struct can_bittiming *); +extern int rtnl_link_can_get_device_stats(struct rtnl_link *, + struct can_device_stats *); + #ifdef __cplusplus } #endif diff --git a/lib/route/link/can.c b/lib/route/link/can.c index 290d42c7..da00144f 100644 --- a/lib/route/link/can.c +++ b/lib/route/link/can.c @@ -41,6 +41,7 @@ #define CAN_HAS_BERR_COUNTER (1<<7) #define CAN_HAS_DATA_BITTIMING (1<<8) #define CAN_HAS_DATA_BITTIMING_CONST (1<<9) +#define CAN_HAS_DEVICE_STATS (1<<10) struct can_info { uint32_t ci_state; @@ -54,6 +55,7 @@ struct can_info { uint32_t ci_mask; struct can_bittiming ci_data_bittiming; struct can_bittiming_const ci_data_bittiming_const; + struct can_device_stats ci_device_stats; }; /** @endcond */ @@ -166,6 +168,11 @@ static int can_parse(struct rtnl_link *link, struct nlattr *data, ci->ci_mask |= CAN_HAS_DATA_BITTIMING_CONST; } + if (xstats && nla_len(xstats) >= sizeof(ci->ci_device_stats)) { + nla_memcpy(&ci->ci_device_stats, xstats, sizeof(ci->ci_device_stats)); + ci->ci_mask |= CAN_HAS_DEVICE_STATS; + } + err = 0; errout: return err; @@ -223,11 +230,8 @@ static void can_dump_line(struct rtnl_link *link, struct nl_dump_params *p) static void can_dump_details(struct rtnl_link *link, struct nl_dump_params *p) { struct can_info *ci = link->l_info; - char buf [64]; - rtnl_link_can_ctrlmode2str(ci->ci_ctrlmode.flags, buf, sizeof(buf)); - nl_dump(p, " bitrate %d %s <%s>", - ci->ci_bittiming.bitrate, print_can_state(ci->ci_state), buf); + can_dump_line(link, p); if (ci->ci_mask & CAN_HAS_RESTART) { if (ci->ci_restart) @@ -286,8 +290,28 @@ static void can_dump_details(struct rtnl_link *link, struct nl_dump_params *p) nl_dump_line(p," bus error TX %d\n", ci->ci_berr_counter.txerr); } +} - return; +static void can_dump_stats(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct can_info *ci = link->l_info; + + can_dump_details(link, p); + + if (ci->ci_mask & CAN_HAS_DEVICE_STATS) { + nl_dump_line(p," bus errors %d\n", + ci->ci_device_stats.bus_error); + nl_dump_line(p," error warning state changes %d\n", + ci->ci_device_stats.error_warning); + nl_dump_line(p," error passive state changes %d\n", + ci->ci_device_stats.error_passive); + nl_dump_line(p," bus off state changes %d\n", + ci->ci_device_stats.bus_off); + nl_dump_line(p," arbitration lost errors %d\n", + ci->ci_device_stats.arbitration_lost); + nl_dump_line(p," restarts %d\n", + ci->ci_device_stats.restarts); + } } static int can_clone(struct rtnl_link *dst, struct rtnl_link *src) @@ -364,6 +388,7 @@ static struct rtnl_link_info_ops can_info_ops = { .io_dump = { [NL_DUMP_LINE] = can_dump_line, [NL_DUMP_DETAILS] = can_dump_details, + [NL_DUMP_STATS] = can_dump_stats, }, .io_clone = can_clone, .io_put_attrs = can_put_attrs, @@ -864,6 +889,30 @@ int rtnl_link_can_set_data_bittiming(struct rtnl_link *link, return 0; } +/** + * Get CAN device stats + * @arg link Link object + * @arg device_stats CAN device stats + * + * @return 0 on success or a negative error code + */ +int rtnl_link_can_get_device_stats(struct rtnl_link* link, + struct can_device_stats *device_stats) +{ + struct can_info *ci = link->l_info; + + IS_CAN_LINK_ASSERT(link); + if (!device_stats) + return -NLE_INVAL; + + if (ci->ci_mask & CAN_HAS_DEVICE_STATS) + *device_stats = ci->ci_device_stats; + else + return -NLE_MISSING_ATTR; + + return 0; +} + /** @} */ /** diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 294d9f94..fa7af455 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1312,4 +1312,5 @@ global: rtnl_link_bond_set_hashing_type; rtnl_link_bond_set_miimon; rtnl_link_bond_set_min_links; + rtnl_link_can_get_device_stats; } libnl_3_8;