Add callbacks to calculate the size and fill link extended statistics which can be split into multiple messages and are dumped via the new rtnl stats API (RTM_GETSTATS) with the IFLA_STATS_LINK_XSTATS attribute. Also add that attribute to the idx mask check since it is expected to be able to save state and resume dumping (e.g. future bridge per-vlan stats will be dumped via this attribute and callbacks). Each link type should nest its private attributes under the per-link type attribute. This allows to have any number of separated private attributes and to avoid one call to get the dev link type.
Unified · Split
| @@ -47,6 +47,9 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh) · 46 unmodified lines | ||
| 47 | 47 | * @get_num_rx_queues: Function to determine number of receive queues |
| 48 | 48 | * to create when creating a new device. |
| 49 | 49 | * @get_link_net: Function to get the i/o netns of the device |
| 50 | + * @get_linkxstats_size: Function to calculate the required room for | |
| 51 | + * dumping device-specific extended link stats | |
| 52 | + * @fill_linkxstats: Function to dump device-specific extended link stats | |
| 50 | 53 | */ |
| 51 | 54 | struct rtnl_link_ops { |
| 52 | 55 | struct list_head list; |
| @@ -95,6 +98,10 @@ struct rtnl_link_ops { · 42 unmodified lines | ||
| 95 | 98 | const struct net_device *dev, |
| 96 | 99 | const struct net_device *slave_dev); |
| 97 | 100 | struct net *(*get_link_net)(const struct net_device *dev); |
| 101 | + size_t (*get_linkxstats_size)(const struct net_device *dev); | |
| 102 | + int (*fill_linkxstats)(struct sk_buff *skb, | |
| 103 | + const struct net_device *dev, | |
| 104 | + int *prividx); | |
| 98 | 105 | }; |
| 99 | 106 | |
| 100 | 107 | int __rtnl_link_register(struct rtnl_link_ops *ops); |
| @@ -810,6 +810,7 @@ struct if_stats_msg { · 809 unmodified lines | ||
| 810 | 810 | enum { |
| 811 | 811 | IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ |
| 812 | 812 | IFLA_STATS_LINK_64, |
| 813 | + IFLA_STATS_LINK_XSTATS, | |
| 813 | 814 | __IFLA_STATS_MAX, |
| 814 | 815 | }; |
| 815 | 816 | |
| @@ -817,4 +818,15 @@ enum { · 1 unmodified line | ||
| 817 | 818 | |
| 818 | 819 | #define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) |
| 819 | 820 | |
| 821 | +/* These are embedded into IFLA_STATS_LINK_XSTATS: | |
| 822 | + * [IFLA_STATS_LINK_XSTATS] | |
| 823 | + * -> [LINK_XSTATS_TYPE_xxx] | |
| 824 | + * -> [rtnl link type specific attributes] | |
| 825 | + */ | |
| 826 | +enum { | |
| 827 | + LINK_XSTATS_TYPE_UNSPEC, | |
| 828 | + __LINK_XSTATS_TYPE_MAX | |
| 829 | +}; | |
| 830 | +#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) | |
| 831 | + | |
| 820 | 832 | #endif /* _UAPI_LINUX_IF_LINK_H */ |
| @@ -3483,6 +3483,26 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, · 3482 unmodified lines | ||
| 3483 | 3483 | dev_get_stats(dev, sp); |
| 3484 | 3484 | } |
| 3485 | 3485 | |
| 3486 | + if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, *idxattr)) { | |
| 3487 | + const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | |
| 3488 | + | |
| 3489 | + if (ops && ops->fill_linkxstats) { | |
| 3490 | + int err; | |
| 3491 | + | |
| 3492 | + *idxattr = IFLA_STATS_LINK_XSTATS; | |
| 3493 | + attr = nla_nest_start(skb, | |
| 3494 | + IFLA_STATS_LINK_XSTATS); | |
| 3495 | + if (!attr) | |
| 3496 | + goto nla_put_failure; | |
| 3497 | + | |
| 3498 | + err = ops->fill_linkxstats(skb, dev, prividx); | |
| 3499 | + nla_nest_end(skb, attr); | |
| 3500 | + if (err) | |
| 3501 | + goto nla_put_failure; | |
| 3502 | + *idxattr = 0; | |
| 3503 | + } | |
| 3504 | + } | |
| 3505 | + | |
| 3486 | 3506 | nlmsg_end(skb, nlh); |
| 3487 | 3507 | |
| 3488 | 3508 | return 0; |
| @@ -3509,6 +3529,16 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev, · 20 unmodified lines | ||
| 3509 | 3529 | if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0)) |
| 3510 | 3530 | size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64)); |
| 3511 | 3531 | |
| 3532 | + if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, 0)) { | |
| 3533 | + const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | |
| 3534 | + | |
| 3535 | + if (ops && ops->get_linkxstats_size) { | |
| 3536 | + size += nla_total_size(ops->get_linkxstats_size(dev)); | |
| 3537 | + /* for IFLA_STATS_LINK_XSTATS */ | |
| 3538 | + size += nla_total_size(0); | |
| 3539 | + } | |
| 3540 | + } | |
| 3541 | + | |
| 3512 | 3542 | return size; |
| 3513 | 3543 | } |
| 3514 | 3544 | |