linux/net/core
Jakub Kicinski 7aa767d0d3 net: consume xmit errors of GSO frames
udpgro_frglist.sh and udpgro_bench.sh are the flakiest tests
currently in NIPA. They fail in the same exact way, TCP GRO
test stalls occasionally and the test gets killed after 10min.

These tests use veth to simulate GRO. They attach a trivial
("return XDP_PASS;") XDP program to the veth to force TSO off
and NAPI on.

Digging into the failure mode we can see that the connection
is completely stuck after a burst of drops. The sender's snd_nxt
is at sequence number N [1], but the receiver claims to have
received (rcv_nxt) up to N + 3 * MSS [2]. Last piece of the puzzle
is that senders rtx queue is not empty (let's say the block in
the rtx queue is at sequence number N - 4 * MSS [3]).

In this state, sender sends a retransmission from the rtx queue
with a single segment, and sequence numbers N-4*MSS:N-3*MSS [3].
Receiver sees it and responds with an ACK all the way up to
N + 3 * MSS [2]. But sender will reject this ack as TCP_ACK_UNSENT_DATA
because it has no recollection of ever sending data that far out [1].
And we are stuck.

The root cause is the mess of the xmit return codes. veth returns
an error when it can't xmit a frame. We end up with a loss event
like this:

  -------------------------------------------------
  |   GSO super frame 1   |   GSO super frame 2   |
  |-----------------------------------------------|
  | seg | seg | seg | seg | seg | seg | seg | seg |
  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |
  -------------------------------------------------
     x    ok    ok    <ok>|  ok    ok    ok   <x>
                          \\
			   snd_nxt

"x" means packet lost by veth, and "ok" means it went thru.
Since veth has TSO disabled in this test it sees individual segments.
Segment 1 is on the retransmit queue and will be resent.

So why did the sender not advance snd_nxt even tho it clearly did
send up to seg 8? tcp_write_xmit() interprets the return code
from the core to mean that data has not been sent at all. Since
TCP deals with GSO super frames, not individual segment the crux
of the problem is that loss of a single segment can be interpreted
as loss of all. TCP only sees the last return code for the last
segment of the GSO frame (in <> brackets in the diagram above).

Of course for the problem to occur we need a setup or a device
without a Qdisc. Otherwise Qdisc layer disconnects the protocol
layer from the device errors completely.

We have multiple ways to fix this.

 1) make veth not return an error when it lost a packet.
    While this is what I think we did in the past, the issue keeps
    reappearing and it's annoying to debug. The game of whack
    a mole is not great.

 2) fix the damn return codes
    We only talk about NETDEV_TX_OK and NETDEV_TX_BUSY in the
    documentation, so maybe we should make the return code from
    ndo_start_xmit() a boolean. I like that the most, but perhaps
    some ancient, not-really-networking protocol would suffer.

 3) make TCP ignore the errors
    It is not entirely clear to me what benefit TCP gets from
    interpreting the result of ip_queue_xmit()? Specifically once
    the connection is established and we're pushing data - packet
    loss is just packet loss?

 4) this fix
    Ignore the rc in the Qdisc-less+GSO case, since it's unreliable.
    We already always return OK in the TCQ_F_CAN_BYPASS case.
    In the Qdisc-less case let's be a bit more conservative and only
    mask the GSO errors. This path is taken by non-IP-"networks"
    like CAN, MCTP etc, so we could regress some ancient thing.
    This is the simplest, but also maybe the hackiest fix?

Similar fix has been proposed by Eric in the past but never committed
because original reporter was working with an OOT driver and wasn't
providing feedback (see Link).

Link: https://lore.kernel.org/CANn89iJcLepEin7EtBETrZ36bjoD9LrR=k4cfwWh046GB+4f9A@mail.gmail.com
Fixes: 1f59533f9c ("qdisc: validate frames going through the direct_xmit path")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260223235100.108939-1-kuba@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-02-26 11:35:00 +01:00
..
bpf_sk_storage.c bpf: Switch to bpf_selem_unlink_nofail in bpf_local_storage_{map_free, destroy} 2026-02-06 14:47:59 -08:00
datagram.c net: datagram: introduce datagram_poll_queue for custom receive queues 2025-10-23 15:46:04 +02:00
dev_addr_lists_test.c net: dev_addr_lists: move locking out of init/exit in kunit 2024-04-15 10:26:35 +01:00
dev_addr_lists.c net: s/dev_pre_changeaddr_notify/netif_pre_changeaddr_notify/ 2025-07-18 17:27:47 -07:00
dev_api.c net: define an enum for the napi threaded state 2025-07-24 18:34:55 -07:00
dev_ioctl.c net: remove legacy way to get/set HW timestamp config 2026-01-20 18:21:27 -08:00
dev.c net: consume xmit errors of GSO frames 2026-02-26 11:35:00 +01:00
dev.h net: add queue config validation callback 2026-01-23 11:49:02 -08:00
devmem.c net: inline net_is_devmem_iov() 2026-01-25 13:18:53 -08:00
devmem.h net: inline net_is_devmem_iov() 2026-01-25 13:18:53 -08:00
drop_monitor.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
dst_cache.c net: dst: annotate data-races around dst->obsolete 2025-07-02 14:32:29 -07:00
dst.c dst: fix races in rt6_uncached_list_del() and rt_del_uncached_list() 2026-01-13 19:08:18 -08:00
failover.c
fib_notifier.c net: do not acquire rtnl in fib_seq_sum() 2024-10-11 15:35:05 -07:00
fib_rules.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net 2025-04-17 12:26:50 -07:00
filter.c bpf-next-7.0 2026-02-10 11:26:21 -08:00
flow_dissector.c net: remove '__' from __skb_flow_get_ports() 2025-02-24 14:27:53 -08:00
flow_offload.c tc: flower: Enable offload support IPSEC SPI field. 2023-08-02 10:09:32 +01:00
gen_estimator.c net_sched: gen_estimator: fix est_timer() vs CONFIG_PREEMPT_RT=y 2025-08-29 19:04:20 -07:00
gen_stats.c
gro_cells.c net: gro_cells: Reduce lock scope in gro_cell_poll 2025-11-05 17:41:29 -08:00
gro.c net/ipv6: Drop HBH for BIG TCP on RX side 2026-02-06 20:50:12 -08:00
gso.c net: introduce struct net_hotdata 2024-03-07 21:12:41 -08:00
hotdata.c net: add net.core.qdisc_max_burst 2026-01-13 10:12:11 +01:00
hwbm.c
ieee8021q_helpers.c net: ieee8021q: fix insufficient table-size assertion 2025-07-01 12:55:49 +02:00
link_watch.c linkwatch: use __dev_put() in callers to prevent UAF 2026-02-02 16:59:18 -08:00
lock_debug.c netdev: fix the locking for netdev notifications 2025-04-17 18:55:14 -07:00
lwt_bpf.c ipv4: Convert ->flowi4_tos to dscp_t. 2025-08-26 17:34:31 -07:00
lwtunnel.c inet: Remove rtnl_is_held arg of lwtunnel_valid_encap_type(_attr)?(). 2025-05-20 19:18:24 -07:00
Makefile net: get rid of net/core/request_sock.c 2026-02-05 09:23:05 -08:00
mp_dmabuf_devmem.h memory-provider: dmabuf devmem memory provider 2024-09-11 20:44:31 -07:00
neighbour.c net: core: neighbour: Make another netlink notification atomically 2026-01-25 14:57:37 -08:00
net_namespace.c netns: optimize netns cleaning by batching unhash_nsid calls 2026-02-06 20:01:31 -08:00
net_test.c pfcp: always set pfcp metadata 2024-04-01 10:49:28 +01:00
net-procfs.c net: add proper RCU protection to /proc/net/ptype 2026-02-03 19:20:30 -08:00
net-sysfs.c net: Keep ignoring isolated cpuset change 2026-02-03 15:23:33 +01:00
net-sysfs.h net: remove RTNL use for /proc/sys/net/core/rps_default_mask 2025-07-07 18:42:12 -07:00
net-traces.c move asm/unaligned.h to linux/unaligned.h 2024-10-02 17:23:23 -04:00
netclassid_cgroup.c netclassid: use thread_group_leader(p) in update_classid_task() 2026-02-03 08:21:26 -08:00
netdev_config.c net: add queue config validation callback 2026-01-23 11:49:02 -08:00
netdev_queues.c Revert "Merge branch 'netkit-support-for-io_uring-zero-copy-and-af_xdp'" 2026-01-20 18:06:01 -08:00
netdev_rx_queue.c net: add queue config validation callback 2026-01-23 11:49:02 -08:00
netdev-genl-gen.c Revert "Merge branch 'netkit-support-for-io_uring-zero-copy-and-af_xdp'" 2026-01-20 18:06:01 -08:00
netdev-genl-gen.h Revert "Merge branch 'netkit-support-for-io_uring-zero-copy-and-af_xdp'" 2026-01-20 18:06:01 -08:00
netdev-genl.c Revert "Merge branch 'netkit-support-for-io_uring-zero-copy-and-af_xdp'" 2026-01-20 18:06:01 -08:00
netevent.c
netmem_priv.h netmem: replace __netmem_clear_lsb() with netmem_to_nmdesc() 2025-10-14 13:37:26 +02:00
netpoll.c net: netpoll: initialize work queue before error checks 2025-11-28 20:16:57 -08:00
netprio_cgroup.c
of_net.c net: Explicitly include correct DT includes 2023-07-27 20:33:16 -07:00
page_pool_priv.h net: page_pool: don't try to stash the napi id 2025-01-27 14:37:41 -08:00
page_pool_user.c net: use napi_id_valid helper 2025-02-17 16:43:04 -08:00
page_pool.c net: page_pool: sanitise allocation order 2025-12-02 11:08:39 -08:00
pktgen.c kernel.h: drop hex.h and update all hex.h users 2026-01-20 19:44:19 -08:00
ptp_classifier.c
rtnetlink.c rtnetlink: honor RTEXT_FILTER_SKIP_STATS in IFLA_STATS 2025-11-04 16:07:37 -08:00
scm.c scm: Convert put_cmsg() to scoped user access 2025-11-18 15:27:34 +01:00
secure_seq.c net: Retire DCCP socket. 2025-04-11 18:58:10 -07:00
selftests.c net: selftests: export packet creation helpers for driver use 2025-11-06 13:38:11 +01:00
skb_fault_injection.c net: Implement fault injection forcing skb reallocation 2024-11-12 12:05:33 +01:00
skbuff.c net: Drop the lock in skb_may_tx_timestamp() 2026-02-24 11:27:29 +01:00
skmsg.c bpf, sockmap: Fix FIONREAD for sockmap 2026-01-27 09:11:30 -08:00
sock_destructor.h
sock_diag.c net: WQ_PERCPU added to alloc_workqueue users 2025-09-22 17:40:30 -07:00
sock_map.c bpf: Remove attach_type in sockmap_link 2025-07-11 10:51:55 -07:00
sock_reuseport.c net: core: annotate socks of struct sock_reuseport with __counted_by 2024-08-02 17:16:59 -07:00
sock.c tcp: reduce tcp sockets size by one cache line 2026-01-30 17:15:51 -08:00
stream.c net: stream: add description for sk_stream_write_space() 2025-07-18 16:57:21 -07:00
sysctl_net_core.c net: include <linux/hex.h> from sysctl_net_core.c 2026-01-26 16:35:53 -08:00
timestamping.c net: Add the possibility to support a selected hwtstamp in netdevice 2024-12-16 12:51:40 +00:00
tso.c move asm/unaligned.h to linux/unaligned.h 2024-10-02 17:23:23 -04:00
utils.c kernel.h: drop hex.h and update all hex.h users 2026-01-20 19:44:19 -08:00
xdp.c bpf: Remove redundant KF_TRUSTED_ARGS flag from all kfuncs 2026-01-02 12:04:28 -08:00