lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250805213356.3348348-3-dechen@redhat.com>
Date: Tue,  5 Aug 2025 17:33:55 -0400
From: Dennis Chen <dechen@...hat.com>
To: netdev@...r.kernel.org
Cc: dechen@...hat.com,
	dchen27@...u.edu,
	kuba@...nel.org,
	davem@...emloft.net,
	edumazet@...gle.com,
	pabeni@...hat.com,
	andrew+netdev@...n.ch,
	petrm@...dia.com
Subject: [PATCH net-next 2/3] netdevsim: Add mock stats for ethtool

Add mock stats exposed through ethtool -S for netdevsim. The stats are
incremented every 100ms. Mock stats are enabled/disabled through a
debugfs toggle.

        # echo y > /sys/kernel/debug/netdevsim/$DEV/ports/0/ethtool/mock_stats/enabled

Signed-off-by: Dennis Chen <dechen@...hat.com>
---
 drivers/net/netdevsim/ethtool.c   | 127 +++++++++++++++++++++++++++++-
 drivers/net/netdevsim/netdev.c    |   1 +
 drivers/net/netdevsim/netdevsim.h |  11 +++
 3 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
index 33d39dfdd6d9..78aea02f8bf1 100644
--- a/drivers/net/netdevsim/ethtool.c
+++ b/drivers/net/netdevsim/ethtool.c
@@ -16,6 +16,10 @@ struct nsim_stat_desc {
 	.desc = #s,  \
 	.offset = offsetof(struct rtnl_link_stats64, s) }
 
+#define NSIM_MOCK_STAT_ENTRY(s) { \
+	.desc = #s,  \
+	.offset = offsetof(struct nsim_mock_stats, s) }
+
 static const struct nsim_stat_desc nsim_stats_desc[] = {
 	NSIM_STAT_ENTRY(tx_packets),
 	NSIM_STAT_ENTRY(rx_packets),
@@ -27,6 +31,14 @@ static const struct nsim_stat_desc nsim_stats_desc[] = {
 
 #define NSIM_STATS_LEN	ARRAY_SIZE(nsim_stats_desc)
 
+#define NSIM_MOCK_STATS_LEN	ARRAY_SIZE(nsim_mock_stats_desc)
+
+static const struct nsim_stat_desc nsim_mock_stats_desc[] = {
+	NSIM_MOCK_STAT_ENTRY(hw_out_of_sequence),
+	NSIM_MOCK_STAT_ENTRY(hw_out_of_buffer),
+	NSIM_MOCK_STAT_ENTRY(hw_packet_seq_err),
+};
+
 static void
 nsim_get_pause_stats(struct net_device *dev,
 		     struct ethtool_pause_stats *pause_stats)
@@ -204,9 +216,12 @@ static int nsim_get_ts_info(struct net_device *dev,
 
 static int nsim_sset_count(struct net_device *dev, int sset)
 {
+	struct netdevsim *ns = netdev_priv(dev);
+
 	switch (sset) {
 	case ETH_SS_STATS:
-		return NSIM_STATS_LEN;
+		return ns->ethtool.mock_stats.enabled ?
+			NSIM_STATS_LEN + NSIM_MOCK_STATS_LEN : NSIM_STATS_LEN;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -214,20 +229,51 @@ static int nsim_sset_count(struct net_device *dev, int sset)
 
 static void nsim_get_strings(struct net_device *dev, u32 sset, u8 *data)
 {
+	struct netdevsim *ns = netdev_priv(dev);
+
 	int i;
 
 	switch (sset) {
 	case ETH_SS_STATS:
 		for (i = 0; i < NSIM_STATS_LEN; i++)
 			ethtool_puts(&data, nsim_stats_desc[i].desc);
+		if (ns->ethtool.mock_stats.enabled)
+			for (i = 0; i < NSIM_MOCK_STATS_LEN; i++)
+				ethtool_puts(&data,
+					     nsim_mock_stats_desc[i].desc);
+
 		break;
 	}
 }
 
+static void nsim_ethtool_add_mock_stats(struct netdevsim *ns,
+					u64 *data)
+{
+	unsigned int start, i;
+	const u8 *stats_base;
+	const u64_stats_t *p;
+	size_t offset;
+
+	stats_base = (const u8 *)&ns->ethtool.mock_stats;
+
+	data += NSIM_STATS_LEN;
+
+	do {
+		start = u64_stats_fetch_begin(&ns->ethtool.mock_stats.syncp);
+		for (i = 0; i < NSIM_MOCK_STATS_LEN; i++) {
+			offset = nsim_mock_stats_desc[i].offset;
+
+			p = (const u64_stats_t *)(stats_base + offset);
+			data[i] = u64_stats_read(p);
+		}
+	} while (u64_stats_fetch_retry(&ns->ethtool.mock_stats.syncp, start));
+}
+
 static void nsim_get_ethtool_stats(struct net_device *dev,
 				   struct ethtool_stats *stats,
 				   u64 *data)
 {
+	struct netdevsim *ns;
 	struct rtnl_link_stats64 rtstats = {};
 	int i;
 
@@ -235,6 +281,33 @@ static void nsim_get_ethtool_stats(struct net_device *dev,
 
 	for (i = 0; i < NSIM_STATS_LEN; i++)
 		data[i] = *(u64 *)((u8 *)&rtstats + nsim_stats_desc[i].offset);
+
+	ns = netdev_priv(dev);
+
+	if (ns->ethtool.mock_stats.enabled)
+		nsim_ethtool_add_mock_stats(ns, data);
+}
+
+#define NSIM_MOCK_STATS_INTERVAL_MS 100
+
+static void nsim_mock_stats_traffic_bump(struct nsim_mock_stats *stats)
+{
+	if (stats->enabled) {
+		stats->hw_out_of_buffer += 1;
+		stats->hw_out_of_sequence += 1;
+		stats->hw_packet_seq_err += 1;
+	}
+}
+
+static void nsim_mock_stats_traffic_work(struct work_struct *work)
+{
+	struct nsim_mock_stats *stats;
+
+	stats = container_of(work, struct nsim_mock_stats, traffic_dw.work);
+	nsim_mock_stats_traffic_bump(stats);
+
+	schedule_delayed_work(&stats->traffic_dw,
+			      msecs_to_jiffies(NSIM_MOCK_STATS_INTERVAL_MS));
 }
 
 static const struct ethtool_ops nsim_ethtool_ops = {
@@ -269,6 +342,44 @@ static void nsim_ethtool_ring_init(struct netdevsim *ns)
 	ns->ethtool.ring.tx_max_pending = 4096;
 }
 
+static void mock_stats_reset(struct nsim_mock_stats *mock_stats)
+{
+	mock_stats->hw_out_of_buffer = 0;
+	mock_stats->hw_out_of_sequence = 0;
+	mock_stats->hw_packet_seq_err = 0;
+}
+
+static ssize_t mock_stats_enabled_write(struct file *filp,
+					const char __user *ubuf,
+					size_t count,
+					loff_t *offp)
+{
+	bool enabled;
+	int r;
+	struct nsim_mock_stats *mock_stats = filp->private_data;
+	struct dentry *dentry = filp->f_path.dentry;
+
+	r = kstrtobool_from_user(ubuf, count, &enabled);
+	if (!r) {
+		r = debugfs_file_get(dentry);
+		if (unlikely(r))
+			return r;
+
+		mock_stats->enabled = enabled;
+		if (!enabled)
+			mock_stats_reset(mock_stats);
+
+		debugfs_file_put(dentry);
+	}
+
+	return count;
+}
+
+static struct debugfs_short_fops mock_stats_fops = {
+	.write = mock_stats_enabled_write,
+	.llseek = generic_file_llseek
+};
+
 void nsim_ethtool_init(struct netdevsim *ns)
 {
 	struct dentry *ethtool, *dir;
@@ -305,4 +416,18 @@ void nsim_ethtool_init(struct netdevsim *ns)
 			   &ns->ethtool.ring.rx_mini_max_pending);
 	debugfs_create_u32("tx_max_pending", 0600, dir,
 			   &ns->ethtool.ring.tx_max_pending);
+
+	dir = debugfs_create_dir("mock_stats", ethtool);
+	debugfs_create_file("enabled", 0600, dir, &ns->ethtool.mock_stats,
+			    &mock_stats_fops);
+
+	INIT_DELAYED_WORK(&ns->ethtool.mock_stats.traffic_dw,
+			  &nsim_mock_stats_traffic_work);
+	schedule_delayed_work(&ns->ethtool.mock_stats.traffic_dw,
+			      msecs_to_jiffies(NSIM_MOCK_STATS_INTERVAL_MS));
+}
+
+void nsim_ethtool_exit(struct netdevsim *ns)
+{
+	cancel_delayed_work_sync(&ns->ethtool.mock_stats.traffic_dw);
 }
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 39fe28af48b9..d1864b7cbbd5 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -1143,6 +1143,7 @@ void nsim_destroy(struct netdevsim *ns)
 	rtnl_unlock();
 	if (nsim_dev_port_is_pf(ns->nsim_dev_port))
 		nsim_exit_netdevsim(ns);
+	nsim_ethtool_exit(ns);
 
 	/* Put this intentionally late to exercise the orphaning path */
 	if (ns->page) {
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index bddd24c1389d..57631ec8887a 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -82,6 +82,15 @@ struct nsim_ethtool_pauseparam {
 	bool report_stats_tx;
 };
 
+struct nsim_mock_stats {
+	u64 hw_out_of_sequence;
+	u64 hw_out_of_buffer;
+	u64 hw_packet_seq_err;
+	struct u64_stats_sync syncp;
+	struct delayed_work traffic_dw;
+	bool enabled;
+};
+
 struct nsim_ethtool {
 	u32 get_err;
 	u32 set_err;
@@ -90,6 +99,7 @@ struct nsim_ethtool {
 	struct ethtool_coalesce coalesce;
 	struct ethtool_ringparam ring;
 	struct ethtool_fecparam fec;
+	struct nsim_mock_stats mock_stats;
 };
 
 struct nsim_rq {
@@ -150,6 +160,7 @@ void nsim_destroy(struct netdevsim *ns);
 bool netdev_is_nsim(struct net_device *dev);
 
 void nsim_ethtool_init(struct netdevsim *ns);
+void nsim_ethtool_exit(struct netdevsim *ns);
 
 void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev);
 int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,
-- 
2.50.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ