[PATCH RFC net-next v4 07/14] xsk: try to skip validating skb list in xmit path

Jason Xing
2026-04-15T08:27:46Z

This patch moves the SG check ahead, which is the only place we need to
handle very carefully because either in xsk_build_skb_zerocopy() or in
multi-buffer mode nr_frags (in skb_needs_linearize()) is used[1].

In most cases, for xsk, it's totally not needed to validate and check
the skb in validate_xmit_skb_list() that adds numerous checks in the
extremely hot path. In this kind of workload, even the overhead of
mathematical operations is not trivial.

Performance-wise, I run './xdpsock -i enp2s0f0np0 -t -S -s 64' on 1Gb/sec
ixgbe driver to verify. It stably goes up by 5.48%

[1]: https://lore.kernel.org/all/20251125115754.46793-1-kerneljasonxing@gmail.com/

Signed-off-by: Jason Xing <kernelxing@tencent.com>
---
net/core/dev.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index a6abd621a7f3..aa38993b9dd4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4899,6 +4899,7 @@ int xsk_direct_xmit_batch(struct xdp_sock *xs, struct net_device *dev)
u16 queue_id = xs->queue_id;
struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_id);
struct sk_buff_head *send_queue = &xs->batch.send_queue;
+ bool need_validate = !(dev->features & NETIF_F_SG);
int ret = NETDEV_TX_BUSY;
struct sk_buff *skb;
bool more = true;
@@ -4906,15 +4907,17 @@ int xsk_direct_xmit_batch(struct xdp_sock *xs, struct net_device *dev)
local_bh_disable();
HARD_TX_LOCK(dev, txq, smp_processor_id());
while ((skb = __skb_dequeue(send_queue)) != NULL) {
- struct sk_buff *orig_skb = skb;
- bool again = false;
-
- skb = validate_xmit_skb_list(skb, dev, &again);
- if (skb != orig_skb) {
- dev_core_stats_tx_dropped_inc(dev);
- kfree_skb_list(skb);
- ret = NET_XMIT_DROP;
- break;
+ if (unlikely(need_validate)) {
+ struct sk_buff *orig_skb = skb;
+ bool again = false;
+
+ skb = validate_xmit_skb_list(skb, dev, &again);
+ if (skb != orig_skb) {
+ dev_core_stats_tx_dropped_inc(dev);
+ kfree_skb_list(skb);
+ ret = NET_XMIT_DROP;
+ break;
+ }
}

if (netif_xmit_frozen_or_drv_stopped(txq)) {
--
2.41.3