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

Till now we had a ndo statistics function that returned SW statistics.
We want to change the "basic" statistics to return HW statistics if
available.
In this case we need to expose a new ndo to return the SW statistics.
Add a new ndo declaration to get SW statistics
Add a function that gets SW statistics if a competible ndo exist

Signed-off-by: Nogah Frankel <nog...@mellanox.com>
Reviewed-by: Ido Schimmel <ido...@mellanox.com>
Signed-off-by: Jiri Pirko <j...@mellanox.com>
---
 include/linux/netdevice.h | 12 ++++++++++++
 net/core/dev.c            | 25 +++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c2f5112..3ac3e8f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -891,6 +891,14 @@ struct tc_to_netdev {
  *        field is written atomically.
  *     3. Update dev->stats asynchronously and atomically, and define
  *        neither operation.
+ *     Driver should return HW statistics, if available.
+ *
+ * struct rtnl_link_stats64* (*ndo_get_sw_stats64)(struct net_device *dev,
+ *                     struct rtnl_link_stats64 *storage);
+ *     Similar to rtnl_link_stats64 but used to get SW statistics,
+ *     if it is possible to get HW and SW statistics separately.
+ *     If this option isn't valid - driver doesn't need to define
+ *     this function.
  *
  * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, __be16 proto, u16 vid);
  *     If device supports VLAN filtering this function is called when a
@@ -1133,6 +1141,9 @@ struct net_device_ops {
 
        struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
                                                     struct rtnl_link_stats64 
*storage);
+       struct rtnl_link_stats64* (*ndo_get_sw_stats64)(struct net_device *dev,
+                                                       struct 
rtnl_link_stats64 *storage);
+
        struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
 
        int                     (*ndo_vlan_rx_add_vid)(struct net_device *dev,
@@ -3755,6 +3766,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device 
*dev,
                                        struct rtnl_link_stats64 *storage);
 void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
                             const struct net_device_stats *netdev_stats);
+int dev_get_sw_stats(struct net_device *dev, struct rtnl_link_stats64 
*storage);
 
 extern int             netdev_max_backlog;
 extern int             netdev_tstamp_prequeue;
diff --git a/net/core/dev.c b/net/core/dev.c
index 12436d1..a69e418 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7376,6 +7376,8 @@ EXPORT_SYMBOL(netdev_stats_to_stats64);
  *     The device driver may provide its own method by setting
  *     dev->netdev_ops->get_stats64 or dev->netdev_ops->get_stats;
  *     otherwise the internal statistics structure is used.
+ *     If device supports both HW & SW statistics - this function should
+ *     return the HW statistics.
  */
 struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                                        struct rtnl_link_stats64 *storage)
@@ -7397,6 +7399,29 @@ struct rtnl_link_stats64 *dev_get_stats(struct 
net_device *dev,
 }
 EXPORT_SYMBOL(dev_get_stats);
 
+/*     dev_get_sw_stats    - get network device SW statistics
+ *     (if it is possible to get HW & SW statistics separately)
+ *     @dev: device to get statistics from
+ *     @storage: place to store stats
+ *
+ *     if exist a function to query the netdev SW statistics get it to storage
+ *     return 0 if did, or -EINVAL if this function doesn't exist
+ */
+int dev_get_sw_stats(struct net_device *dev,
+                    struct rtnl_link_stats64 *storage)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       if (ops->ndo_get_sw_stats64) {
+               memset(storage, 0, sizeof(*storage));
+               ops->ndo_get_sw_stats64(dev, storage);
+       } else {
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(dev_get_sw_stats);
+
 struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 {
        struct netdev_queue *queue = dev_ingress_queue(dev);
-- 
2.5.5

Reply via email to