[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250506154117.10651-1-alex-shalimov@yandex-team.ru>
Date: Tue, 6 May 2025 18:41:17 +0300
From: Alexander Shalimov <alex-shalimov@...dex-team.ru>
To: netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Cc: willemdebruijn.kernel@...il.com,
jasowang@...hat.com,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
Alexander Shalimov <alex-shalimov@...dex-team.ru>
Subject: [PATCH] net/tun: expose queue utilization stats via ethtool
TUN/TAP devices are heavily used in network virtualization scenarios
such as QEMU/KVM with "-netdev tap" and are commonly paired with virtio-net
or vhost-net backends. Under high network load, queues of the tuntap device
may become saturated, resulting in TX drops.
Existing aggregated drop counters alone are often insufficient during
complex debugging and performance tuning, especially in high-throughput
environments. Visibility of real-time queue utilization is critical for
understanding why guest VMs might be unable to dequeue packets in time.
This patch exposes per-queue utilization statistics via ethtool -S,
allowing on-demand inspection of queue fill levels. Utilization metrics are
captured at the time of the ethtool invocation, providing a snapshot useful
for correlation with guest and host behavior.
Signed-off-by: Alexander Shalimov <alex-shalimov@...dex-team.ru>
---
drivers/net/tun.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 7babd1e9a378..122327e591a5 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -3537,6 +3537,57 @@ static void tun_get_channels(struct net_device *dev,
channels->max_combined = tun->flags & IFF_MULTI_QUEUE ? MAX_TAP_QUEUES : 1;
}
+static void tun_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ char *p = (char *)buf;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < dev->real_num_tx_queues; i++) {
+ snprintf(p, ETH_GSTRING_LEN, "tx_queue_usage_%u", i);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int tun_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return dev->real_num_tx_queues;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void tun_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+ struct tun_file *tfile;
+ int i;
+ int producer, consumer, size, usage;
+
+ rcu_read_lock();
+ for (i = 0; i < dev->real_num_tx_queues; i++) {
+ tfile = rcu_dereference(tun->tfiles[i]);
+
+ producer = READ_ONCE(tfile->tx_ring.producer);
+ consumer = READ_ONCE(tfile->tx_ring.consumer_head);
+ size = READ_ONCE(tfile->tx_ring.size);
+
+ if (producer >= consumer)
+ usage = producer - consumer;
+ else
+ usage = size - (consumer - producer);
+
+ data[i] = usage;
+ }
+ rcu_read_unlock();
+}
+
static const struct ethtool_ops tun_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES,
.get_drvinfo = tun_get_drvinfo,
@@ -3549,6 +3600,9 @@ static const struct ethtool_ops tun_ethtool_ops = {
.set_coalesce = tun_set_coalesce,
.get_link_ksettings = tun_get_link_ksettings,
.set_link_ksettings = tun_set_link_ksettings,
+ .get_strings = tun_get_strings,
+ .get_sset_count = tun_get_sset_count,
+ .get_ethtool_stats = tun_get_ethtool_stats,
};
static int tun_queue_resize(struct tun_struct *tun)
--
2.39.5 (Apple Git-154)
Powered by blists - more mailing lists