From: Nogah Frankel <nog...@mellanox.com>

If there is a dedicated ndo to return SW stats - use
it. Otherwise (indicates that there is no HW stats) use
the default stats ndo.
Return results under IFLA_STATS_LINK_SW_64.

Signed-off-by: Nogah Frankel <nog...@mellanox.com>
Reviewed-by: Ido Schimmel <ido...@mellanox.com>
Signed-off-by: Jiri Pirko <j...@mellanox.com>
---
 include/uapi/linux/if_link.h |  1 +
 net/core/rtnetlink.c         | 35 +++++++++++++++++++++++++++++------
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 98175e7..fcfb944 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -823,6 +823,7 @@ enum {
        IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
        IFLA_STATS_LINK_64,
        IFLA_STATS_LINK_XSTATS,
+       IFLA_STATS_LINK_SW_64,
        __IFLA_STATS_MAX,
 };
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a127d67..f8b12e4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3481,6 +3481,9 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, 
struct net_device *dev,
        struct nlmsghdr *nlh;
        struct nlattr *attr;
        int s_prividx = *prividx;
+       struct rtnl_link_stats64 *sp;
+       struct rtnl_link_stats64 *stats64_sp = 0;
+       int err;
 
        ASSERT_RTNL();
 
@@ -3493,24 +3496,20 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, 
struct net_device *dev,
        ifsm->filter_mask = filter_mask;
 
        if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, *idxattr)) {
-               struct rtnl_link_stats64 *sp;
-
                attr = nla_reserve_64bit(skb, IFLA_STATS_LINK_64,
                                         sizeof(struct rtnl_link_stats64),
                                         IFLA_STATS_UNSPEC);
                if (!attr)
                        goto nla_put_failure;
 
-               sp = nla_data(attr);
-               dev_get_stats(dev, sp);
+               stats64_sp = nla_data(attr);
+               dev_get_stats(dev, stats64_sp);
        }
 
        if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, *idxattr)) {
                const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
 
                if (ops && ops->fill_linkxstats) {
-                       int err;
-
                        *idxattr = IFLA_STATS_LINK_XSTATS;
                        attr = nla_nest_start(skb,
                                              IFLA_STATS_LINK_XSTATS);
@@ -3525,6 +3524,27 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, 
struct net_device *dev,
                }
        }
 
+       if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_SW_64, *idxattr)) {
+               attr = nla_reserve_64bit(skb, IFLA_STATS_LINK_SW_64,
+                                        sizeof(struct rtnl_link_stats64),
+                                        IFLA_STATS_UNSPEC);
+               if (!attr)
+                       goto nla_put_failure;
+
+               sp = nla_data(attr);
+               err = dev_get_sw_stats(dev, sp);
+               if (err) {
+                       /* if err it means there is no dedicated ndo to
+                        * get SW stats - so it is returned by the default
+                        * stats ndo
+                        */
+                       if (stats64_sp)
+                               copy_rtnl_link_stats64(sp, stats64_sp);
+                       else
+                               dev_get_stats(dev, sp);
+               }
+       }
+
        nlmsg_end(skb, nlh);
 
        return 0;
@@ -3541,6 +3561,7 @@ nla_put_failure:
 
 static const struct nla_policy ifla_stats_policy[IFLA_STATS_MAX + 1] = {
        [IFLA_STATS_LINK_64]    = { .len = sizeof(struct rtnl_link_stats64) },
+       [IFLA_STATS_LINK_SW_64] = { .len = sizeof(struct rtnl_link_stats64) },
 };
 
 static size_t if_nlmsg_stats_size(const struct net_device *dev,
@@ -3550,6 +3571,8 @@ static size_t if_nlmsg_stats_size(const struct net_device 
*dev,
 
        if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0))
                size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64));
+       if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_SW_64, 0))
+               size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64));
 
        if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, 0)) {
                const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
-- 
2.5.5

Reply via email to