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 | * @get_num_rx_queues: Function to determine number of receive queues | 47 | * @get_num_rx_queues: Function to determine number of receive queues |
| 48 | * to create when creating a new device. | 48 | * to create when creating a new device. |
| 49 | * @get_link_net: Function to get the i/o netns of the device | 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 | struct rtnl_link_ops { | 54 | struct rtnl_link_ops { |
| 52 | struct list_head list; | 55 | struct list_head list; |
| @@ -95,6 +98,10 @@ struct rtnl_link_ops { · 42 unmodified lines | |||
| 95 | const struct net_device *dev, | 98 | const struct net_device *dev, |
| 96 | const struct net_device *slave_dev); | 99 | const struct net_device *slave_dev); |
| 97 | struct net *(*get_link_net)(const struct net_device *dev); | 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 | int __rtnl_link_register(struct rtnl_link_ops *ops); | 107 | int __rtnl_link_register(struct rtnl_link_ops *ops); |
| @@ -810,6 +810,7 @@ struct if_stats_msg { · 809 unmodified lines | |||
| 810 | enum { | 810 | enum { |
| 811 | IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ | 811 | IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ |
| 812 | IFLA_STATS_LINK_64, | 812 | IFLA_STATS_LINK_64, |
| 813 | IFLA_STATS_LINK_XSTATS, | ||
| 813 | __IFLA_STATS_MAX, | 814 | __IFLA_STATS_MAX, |
| 814 | }; | 815 | }; |
| 815 | 816 | ||
| @@ -817,4 +818,15 @@ enum { · 1 unmodified line | |||
| 817 | 818 | ||
| 818 | #define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) | 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 | #endif /* _UAPI_LINUX_IF_LINK_H */ | 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 | dev_get_stats(dev, sp); | 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 | nlmsg_end(skb, nlh); | 3506 | nlmsg_end(skb, nlh); |
| 3487 | 3507 | ||
| 3488 | return 0; | 3508 | return 0; |
| @@ -3509,6 +3529,16 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev, · 20 unmodified lines | |||
| 3509 | if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0)) | 3529 | if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0)) |
| 3510 | size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64)); | 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 | return size; | 3542 | return size; |
| 3513 | } | 3543 | } |
| 3514 | 3544 | ||