[net-next v6 11/12] net: netdevsim: Add support for SW USO
From: Joe Damato <hidden>
Date: 2026-03-26 23:53:10
Also in:
lkml
Subsystem:
netdevsim, networking drivers, the rest · Maintainers:
Jakub Kicinski, Andrew Lunn, "David S. Miller", Eric Dumazet, Paolo Abeni, Linus Torvalds
Add support for UDP Segmentation Offloading in software (SW USO). This
is helpful for testing when real hardware is not available. A test which
uses this codepath will be added in a following commit.
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Joe Damato <redacted>
---
v5:
- Added Pavan's Reviewed-by. No functional changes.
v4:
- Added parentheses around the gso_type check for clarity. No functional
change.
rfcv2:
- new in rfcv2
drivers/net/netdevsim/netdev.c | 100 ++++++++++++++++++++++++++++++++-
1 file changed, 99 insertions(+), 1 deletion(-)
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index c71b8d116f18..f228bcf3d190 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c@@ -30,6 +30,7 @@ #include <net/rtnetlink.h> #include <net/udp_tunnel.h> #include <net/busy_poll.h> +#include <net/tso.h> #include "netdevsim.h"
@@ -120,6 +121,98 @@ static int nsim_forward_skb(struct net_device *tx_dev, return nsim_napi_rx(tx_dev, rx_dev, rq, skb); } +static netdev_tx_t nsim_uso_segment_xmit(struct net_device *dev, + struct sk_buff *skb) +{ + unsigned int hdr_len, mss, total_payload, num_segs; + struct netdevsim *ns = netdev_priv(dev); + struct net_device *peer_dev; + unsigned int total_len = 0; + struct netdevsim *peer_ns; + struct nsim_rq *rq; + struct tso_t tso; + int i, rxq; + + hdr_len = tso_start(skb, &tso); + mss = skb_shinfo(skb)->gso_size; + total_payload = skb->len - hdr_len; + num_segs = DIV_ROUND_UP(total_payload, mss); + + udp_hdr(skb)->check = 0; + if (!tso.ipv6) + ip_hdr(skb)->check = 0; + + rcu_read_lock(); + peer_ns = rcu_dereference(ns->peer); + if (!peer_ns) + goto out_drop_free; + + peer_dev = peer_ns->netdev; + rxq = skb_get_queue_mapping(skb); + if (rxq >= peer_dev->num_rx_queues) + rxq = rxq % peer_dev->num_rx_queues; + rq = peer_ns->rq[rxq]; + + for (i = 0; i < num_segs; i++) { + unsigned int seg_payload = min_t(unsigned int, mss, + total_payload); + bool last = (i == num_segs - 1); + unsigned int seg_remaining; + struct sk_buff *seg; + + seg = alloc_skb(hdr_len + seg_payload, GFP_ATOMIC); + if (!seg) + break; + + seg->dev = dev; + + tso_build_hdr(skb, skb_put(seg, hdr_len), &tso, + seg_payload, last); + + if (!tso.ipv6) { + unsigned int nh_off = skb_network_offset(skb); + struct iphdr *iph; + + iph = (struct iphdr *)(seg->data + nh_off); + iph->check = ip_fast_csum(iph, iph->ihl); + } + + seg_remaining = seg_payload; + while (seg_remaining > 0) { + unsigned int chunk = min_t(unsigned int, tso.size, + seg_remaining); + + memcpy(skb_put(seg, chunk), tso.data, chunk); + tso_build_data(skb, &tso, chunk); + seg_remaining -= chunk; + } + + total_payload -= seg_payload; + + seg->ip_summed = CHECKSUM_UNNECESSARY; + + if (nsim_forward_skb(dev, peer_dev, seg, rq, NULL) == NET_RX_DROP) + continue; + + total_len += hdr_len + seg_payload; + } + + if (!hrtimer_active(&rq->napi_timer)) + hrtimer_start(&rq->napi_timer, us_to_ktime(5), + HRTIMER_MODE_REL); + + rcu_read_unlock(); + dev_kfree_skb(skb); + dev_dstats_tx_add(dev, total_len); + return NETDEV_TX_OK; + +out_drop_free: + dev_kfree_skb(skb); + rcu_read_unlock(); + dev_dstats_tx_dropped(dev); + return NETDEV_TX_OK; +} + static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct netdevsim *ns = netdev_priv(dev);
@@ -132,6 +225,10 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) int rxq; int dr; + if (skb_is_gso(skb) && + skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) + return nsim_uso_segment_xmit(dev, skb); + rcu_read_lock(); if (!nsim_ipsec_tx(ns, skb)) goto out_drop_any;
@@ -938,7 +1035,8 @@ static void nsim_setup(struct net_device *dev) NETIF_F_HW_CSUM | NETIF_F_LRO | NETIF_F_TSO | - NETIF_F_LOOPBACK; + NETIF_F_LOOPBACK | + NETIF_F_GSO_UDP_L4; dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS; dev->max_mtu = ETH_MAX_MTU; dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_HW_OFFLOAD;
--
2.52.0