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         | 36 ++++++++++++++++++++++++++++++------
 2 files changed, 31 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 7958cde..eed015285 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3490,10 +3490,13 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, 
struct net_device *dev,
                               unsigned int flags, unsigned int filter_mask,
                               int *idxattr, int *prividx)
 {
+       struct rtnl_link_stats64 *stats64_sp = NULL;
+       struct rtnl_link_stats64 *sp;
        struct if_stats_msg *ifsm;
        struct nlmsghdr *nlh;
        struct nlattr *attr;
        int s_prividx = *prividx;
+       int err;
 
        ASSERT_RTNL();
 
@@ -3506,24 +3509,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);
@@ -3538,6 +3537,28 @@ 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);
+
+               if (dev_have_sw_stats(dev)) {
+                       dev_get_sw_stats(dev, sp);
+               } else {
+                       /* if SW stats are not available we return default
+                        * stats. We query only if we don't already have them.
+                        */
+                       if (stats64_sp)
+                               memcpy(sp, stats64_sp, sizeof(*sp));
+                       else
+                               dev_get_stats(dev, sp);
+               }
+       }
+
        nlmsg_end(skb, nlh);
 
        return 0;
@@ -3554,6 +3575,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,
@@ -3563,6 +3585,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