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).

Signed-off-by: Nikolay Aleksandrov <niko...@cumulusnetworks.com>
---
 include/net/rtnetlink.h      |  6 +++++-
 include/uapi/linux/if_link.h |  8 ++++++++
 net/core/rtnetlink.c         | 26 ++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 3f3b0b1b8722..b449c1f3416f 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -95,6 +95,10 @@ struct rtnl_link_ops {
                                                   const struct net_device *dev,
                                                   const struct net_device 
*slave_dev);
        struct net              *(*get_link_net)(const struct net_device *dev);
+       size_t                  (*get_linkxstats_size)(const struct net_device 
*dev);
+       int                     (*fill_linkxstats)(struct sk_buff *skb,
+                                                  const struct net_device *dev,
+                                                  int *lidx);
 };
 
 int __rtnl_link_register(struct rtnl_link_ops *ops);
@@ -154,6 +158,6 @@ int rtnl_nla_parse_ifla(struct nlattr **tb, const struct 
nlattr *head, int len);
  * IFLA_STATS_IDX_ATTR_MASK has all the idx saving attributes set and is
  * used to check if more than one is being requested
  */
-#define IFLA_STATS_IDX_ATTR_MASK 0
+#define IFLA_STATS_IDX_ATTR_MASK IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS)
 
 #endif
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index ba69d4447249..1b874e26b15b 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -798,6 +798,7 @@ struct if_stats_msg {
 enum {
        IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
        IFLA_STATS_LINK_64,
+       IFLA_STATS_LINK_XSTATS,
        __IFLA_STATS_MAX,
 };
 
@@ -805,4 +806,11 @@ enum {
 
 #define IFLA_STATS_FILTER_BIT(ATTR)    (1 << (ATTR - 1))
 
+/* These are embedded into IFLA_STATS_LINK_XSTATS */
+enum {
+       LINK_XSTATS_UNSPEC,
+       __LINK_XSTATS_MAX
+};
+#define LINK_XSTATS_MAX (__LINK_XSTATS_MAX - 1)
+
 #endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ea03b6cd3d3c..9637618c408d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3477,6 +3477,23 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, 
struct net_device *dev,
                dev_get_stats(dev, sp);
        }
 
+       if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS)) {
+               const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
+
+               if (ops && ops->fill_linkxstats) {
+                       int err;
+
+                       attr = nla_nest_start(skb, IFLA_STATS_LINK_XSTATS);
+                       if (!attr)
+                               goto nla_put_failure;
+
+                       err = ops->fill_linkxstats(skb, dev, lidx);
+                       nla_nest_end(skb, attr);
+                       if (err)
+                               goto nla_put_failure;
+               }
+       }
+
        nlmsg_end(skb, nlh);
 
        return 0;
@@ -3503,6 +3520,15 @@ static size_t if_nlmsg_stats_size(const struct 
net_device *dev,
        if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_64))
                size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64));
 
+       if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS)) {
+               const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
+
+               if (ops && ops->get_linkxstats_size)
+                       size += nla_total_size(ops->get_linkxstats_size(dev));
+               /* anything dumped is embedded in IFLA_STATS_LINK_XSTATS */
+               size += nla_total_size(0);
+       }
+
        return size;
 }
 
-- 
2.4.11

Reply via email to