]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net: core: Implement dstats-type stats collections
authorJeremy Kerr <jk@codeconstruct.com.au>
Fri, 7 Jun 2024 10:25:25 +0000 (18:25 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 12 Jun 2024 02:24:56 +0000 (19:24 -0700)
We currently have dev_get_tstats64() for collecting per-cpu stats of
type pcpu_sw_netstats ("tstats"). However, tstats doesn't allow for
accounting tx/rx drops. We do have a stats variant that does have stats
for dropped packets: struct pcpu_dstats, but there are no core helpers
for using those stats.

The VRF driver uses dstats, by providing its own collation/fetch
functions to do so.

This change adds a common implementation for dstats-type collection,
used when pcpu_stat_type == NETDEV_PCPU_STAT_DSTAT. This is based on the
VRF driver's existing stats collator (plus the unused tx_drops stat from
there). We will switch the VRF driver to use this in the next change.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20240607-dstats-v3-2-cc781fe116f7@codeconstruct.com.au
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/dev.c

index e62698c7a0e63bdcbf9589a2d59398eca56a7b46..c361a7b69da86743a0ee81948755c3e6d678c411 100644 (file)
@@ -10703,6 +10703,54 @@ void netdev_run_todo(void)
                wake_up(&netdev_unregistering_wq);
 }
 
+/* Collate per-cpu network dstats statistics
+ *
+ * Read per-cpu network statistics from dev->dstats and populate the related
+ * fields in @s.
+ */
+static void dev_fetch_dstats(struct rtnl_link_stats64 *s,
+                            const struct pcpu_dstats __percpu *dstats)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               u64 rx_packets, rx_bytes, rx_drops;
+               u64 tx_packets, tx_bytes, tx_drops;
+               const struct pcpu_dstats *stats;
+               unsigned int start;
+
+               stats = per_cpu_ptr(dstats, cpu);
+               do {
+                       start = u64_stats_fetch_begin(&stats->syncp);
+                       rx_packets = u64_stats_read(&stats->rx_packets);
+                       rx_bytes   = u64_stats_read(&stats->rx_bytes);
+                       rx_drops   = u64_stats_read(&stats->rx_drops);
+                       tx_packets = u64_stats_read(&stats->tx_packets);
+                       tx_bytes   = u64_stats_read(&stats->tx_bytes);
+                       tx_drops   = u64_stats_read(&stats->tx_drops);
+               } while (u64_stats_fetch_retry(&stats->syncp, start));
+
+               s->rx_packets += rx_packets;
+               s->rx_bytes   += rx_bytes;
+               s->rx_dropped += rx_drops;
+               s->tx_packets += tx_packets;
+               s->tx_bytes   += tx_bytes;
+               s->tx_dropped += tx_drops;
+       }
+}
+
+/* ndo_get_stats64 implementation for dtstats-based accounting.
+ *
+ * Populate @s from dev->stats and dev->dstats. This is used internally by the
+ * core for NETDEV_PCPU_STAT_DSTAT-type stats collection.
+ */
+static void dev_get_dstats64(const struct net_device *dev,
+                            struct rtnl_link_stats64 *s)
+{
+       netdev_stats_to_stats64(s, &dev->stats);
+       dev_fetch_dstats(s, dev->dstats);
+}
+
 /* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
  * all the same fields in the same order as net_device_stats, with only
  * the type differing, but rtnl_link_stats64 may have additional fields
@@ -10779,6 +10827,8 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
        } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
                dev_get_tstats64(dev, storage);
+       } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_DSTATS) {
+               dev_get_dstats64(dev, storage);
        } else {
                netdev_stats_to_stats64(storage, &dev->stats);
        }