Skip to content

Client TUN offload (1/3): pre-existing bug fixes - #502

Merged
xv-thomas-leong merged 5 commits into
mainfrom
main-tun-offload-fixes
Aug 17, 2026
Merged

Client TUN offload (1/3): pre-existing bug fixes#502
xv-thomas-leong merged 5 commits into
mainfrom
main-tun-offload-fixes

Conversation

@xv-thomas-leong

@xv-thomas-leong xv-thomas-leong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Part 1 of 3 — pre-existing bug fixes

First of a three-PR stack that adds client-side TUN GSO/GRO offload. This
part lands only the bug fixes for issues that already exist on main,
independent of the offload feature. Each commit message calls out that it
is a pre-existing bug and how it is fixed. Kept in front and reviewable on
its own so the fixes can merge without waiting on the feature work.

See the stack button right below the title to navigate between PRs.

How Has This Been Tested?

CI and Manually tested

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • The correct base branch is being used, if not main

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code coverage summary for 2e36b27:

Filename                                                          Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
lightway-app-utils/src/args/cipher.rs                                   5                 5     0.00%           1                 1     0.00%           5                 5     0.00%           0                 0         -
lightway-app-utils/src/args/connection_type.rs                         11                 5    54.55%           3                 1    66.67%          11                 5    54.55%           0                 0         -
lightway-app-utils/src/args/duration.rs                               121                22    81.82%          11                 5    54.55%          64                15    76.56%           0                 0         -
lightway-app-utils/src/args/ip_map.rs                                  27                27     0.00%           5                 5     0.00%          19                19     0.00%           0                 0         -
lightway-app-utils/src/args/keyshare.rs                                 5                 5     0.00%           1                 1     0.00%           5                 5     0.00%           0                 0         -
lightway-app-utils/src/args/logging.rs                                 37                37     0.00%           3                 3     0.00%          31                31     0.00%           0                 0         -
lightway-app-utils/src/args/nonzero_duration.rs                       128                24    81.25%          10                 4    60.00%          68                16    76.47%           0                 0         -
lightway-app-utils/src/connection_ticker.rs                           229                17    92.58%          28                 4    85.71%         126                15    88.10%           0                 0         -
lightway-app-utils/src/dplpmtud_timer.rs                              209                13    93.78%          22                 4    81.82%         117                11    90.60%           0                 0         -
lightway-app-utils/src/event_stream.rs                                 19                 0   100.00%           3                 0   100.00%          11                 0   100.00%           0                 0         -
lightway-app-utils/src/metrics.rs                                       4                 4     0.00%           2                 2     0.00%           4                 4     0.00%           0                 0         -
lightway-app-utils/src/network_change_monitor.rs                      348                87    75.00%          29                 8    72.41%         200                75    62.50%           0                 0         -
lightway-app-utils/src/packet_codec.rs                                  2                 2     0.00%           1                 1     0.00%           1                 1     0.00%           0                 0         -
lightway-app-utils/src/sockopt/ip_mtu_discover.rs                      81                81     0.00%           6                 6     0.00%          72                72     0.00%           0                 0         -
lightway-app-utils/src/sockopt/ip_pktinfo.rs                           14                 1    92.86%           1                 0   100.00%          16                 1    93.75%           0                 0         -
lightway-app-utils/src/tun.rs                                         452               452     0.00%          45                45     0.00%         290               290     0.00%           0                 0         -
lightway-app-utils/src/utils.rs                                        21                21     0.00%           1                 1     0.00%          11                11     0.00%           0                 0         -
lightway-boring/src/aes256.rs                                         224                 5    97.77%          13                 0   100.00%          97                 0   100.00%           0                 0         -
lightway-boring/src/cert.rs                                            15                 1    93.33%           1                 0   100.00%           7                 0   100.00%           0                 0         -
lightway-boring/src/chacha20_poly1305.rs                              232                 6    97.41%          16                 3    81.25%         107                 3    97.20%           0                 0         -
lightway-boring/src/config.rs                                          89                16    82.02%          14                 4    71.43%          69                14    79.71%           0                 0         -
lightway-boring/src/context.rs                                        389                89    77.12%          31                 6    80.65%         247                35    85.83%           0                 0         -
lightway-boring/src/error.rs                                           37                 8    78.38%           4                 2    50.00%          28                 6    78.57%           0                 0         -
lightway-boring/src/session.rs                                        809               157    80.59%          52                 7    86.54%         442                97    78.05%           0                 0         -
lightway-boring/src/test_utils.rs                                     329                35    89.36%          25                 5    80.00%         210                24    88.57%           0                 0         -
lightway-boring/src/types.rs                                          132                 9    93.18%          15                 1    93.33%          87                 8    90.80%           0                 0         -
lightway-client/src/config.rs                                         447               105    76.51%          22                 8    63.64%         294                67    77.21%           0                 0         -
lightway-client/src/dns_manager.rs                                     18                18     0.00%           4                 4     0.00%          16                16     0.00%           0                 0         -
lightway-client/src/io/inside.rs                                        3                 3     0.00%           1                 1     0.00%           3                 3     0.00%           0                 0         -
lightway-client/src/io/inside/tun.rs                                   86                86     0.00%          13                13     0.00%          63                63     0.00%           0                 0         -
lightway-client/src/io/outside.rs                                      14                14     0.00%           2                 2     0.00%          12                12     0.00%           0                 0         -
lightway-client/src/io/outside/tcp.rs                                 131               131     0.00%          15                15     0.00%          86                86     0.00%           0                 0         -
lightway-client/src/io/outside/udp.rs                                 220               220     0.00%          21                21     0.00%         151               151     0.00%           0                 0         -
lightway-client/src/io/outside/udp/batch_receive.rs                    99                13    86.87%          11                 1    90.91%          84                13    84.52%           0                 0         -
lightway-client/src/keepalive.rs                                      687                45    93.45%          59                 6    89.83%         357                24    93.28%           0                 0         -
lightway-client/src/lib.rs                                           1431               855    40.25%         109                60    44.95%        1009               663    34.29%           0                 0         -
lightway-client/src/main.rs                                           277               277     0.00%          17                17     0.00%         157               157     0.00%           0                 0         -
lightway-client/src/platform/linux/dns_manager.rs                     118                91    22.88%          14                 9    35.71%          87                62    28.74%           0                 0         -
lightway-client/src/platform/linux/dns_manager/direct_file.rs         106                42    60.38%          12                 6    50.00%          65                29    55.38%           0                 0         -
lightway-client/src/platform/linux/dns_manager/resolvconf.rs           61                61     0.00%           8                 8     0.00%          52                52     0.00%           0                 0         -
lightway-client/src/platform/linux/dns_manager/resolvectl.rs           41                41     0.00%           5                 5     0.00%          34                34     0.00%           0                 0         -
lightway-client/src/route_manager.rs                                 1161               142    87.77%          79                 4    94.94%         640                69    89.22%           0                 0         -
lightway-core/src/borrowed_bytesmut.rs                                373                 0   100.00%          24                 0   100.00%         185                 0   100.00%           0                 0         -
lightway-core/src/builder_predicates.rs                                24                12    50.00%           4                 2    50.00%          24                12    50.00%           0                 0         -
lightway-core/src/cipher.rs                                           197                21    89.34%          10                 0   100.00%          99                 4    95.96%           0                 0         -
lightway-core/src/connection.rs                                      2119               828    60.92%          95                22    76.84%        1518               565    62.78%           0                 0         -
lightway-core/src/connection/builders.rs                              252                46    81.75%          22                 8    63.64%         260                53    79.62%           0                 0         -
lightway-core/src/connection/dplpmtud.rs                             1741                81    95.35%          63                 0   100.00%         830                 7    99.16%           0                 0         -
lightway-core/src/connection/expresslane.rs                            88                 0   100.00%          10                 0   100.00%          74                 0   100.00%           0                 0         -
lightway-core/src/connection/fragment_map.rs                          366                 6    98.36%          25                 0   100.00%         254                 3    98.82%           0                 0         -
lightway-core/src/connection/io_adapter.rs                            882               154    82.54%          56                 9    83.93%         470                98    79.15%           0                 0         -
lightway-core/src/connection/key_update.rs                             34                13    61.76%           5                 0   100.00%          38                19    50.00%           0                 0         -
lightway-core/src/context.rs                                          219                42    80.82%          29                 8    72.41%         243                46    81.07%           0                 0         -
lightway-core/src/context/ip_pool.rs                                    8                 3    62.50%           1                 0   100.00%           5                 0   100.00%           0                 0         -
lightway-core/src/context/server_auth.rs                               37                37     0.00%           4                 4     0.00%          26                26     0.00%           0                 0         -
lightway-core/src/encoding_request_states.rs                            3                 0   100.00%           1                 0   100.00%           3                 0   100.00%           0                 0         -
lightway-core/src/gso.rs                                             1021                96    90.60%          37                 3    91.89%         490                59    87.96%           0                 0         -
lightway-core/src/io.rs                                                10                10     0.00%           3                 3     0.00%           9                 9     0.00%           0                 0         -
lightway-core/src/keyshare.rs                                           5                 0   100.00%           1                 0   100.00%           5                 0   100.00%           0                 0         -
lightway-core/src/lib.rs                                                9                 0   100.00%           3                 0   100.00%           9                 0   100.00%           0                 0         -
lightway-core/src/metrics.rs                                           81                66    18.52%          33                27    18.18%          73                58    20.55%           0                 0         -
lightway-core/src/packet.rs                                            38                10    73.68%           4                 1    75.00%          30                 6    80.00%           0                 0         -
lightway-core/src/plugin.rs                                           307                17    94.46%          22                 4    81.82%         148                10    93.24%           0                 0         -
lightway-core/src/tls/mod.rs                                            4                 4     0.00%           1                 1     0.00%           3                 3     0.00%           0                 0         -
lightway-core/src/utils.rs                                            341                28    91.79%          24                 3    87.50%         170                18    89.41%           0                 0         -
lightway-core/src/version.rs                                           93                 0   100.00%          17                 0   100.00%          82                 0   100.00%           0                 0         -
lightway-core/src/wire.rs                                             438                39    91.10%          29                 0   100.00%         235                 9    96.17%           0                 0         -
lightway-core/src/wire/auth_failure.rs                                 27                 1    96.30%           3                 0   100.00%          17                 0   100.00%           0                 0         -
lightway-core/src/wire/auth_request.rs                                684                57    91.67%          34                 1    97.06%         351                24    93.16%           0                 0         -
lightway-core/src/wire/auth_success_with_config_ipv4.rs               222                 3    98.65%          11                 0   100.00%         124                 0   100.00%           0                 0         -
lightway-core/src/wire/data.rs                                         51                 1    98.04%           5                 0   100.00%          33                 0   100.00%           0                 0         -
lightway-core/src/wire/data_frag.rs                                   127                 1    99.21%          14                 0   100.00%          80                 0   100.00%           0                 0         -
lightway-core/src/wire/encoding_request.rs                             82                 2    97.56%           6                 0   100.00%          42                 1    97.62%           0                 0         -
lightway-core/src/wire/encoding_response.rs                            82                 2    97.56%           6                 0   100.00%          42                 1    97.62%           0                 0         -
lightway-core/src/wire/expresslane_config.rs                          188                 1    99.47%          10                 0   100.00%         113                 0   100.00%           0                 0         -
lightway-core/src/wire/expresslane_data.rs                             48                21    56.25%           5                 2    60.00%          52                23    55.77%           0                 0         -
lightway-core/src/wire/ping.rs                                         95                 2    97.89%           7                 0   100.00%          59                 0   100.00%           0                 0         -
lightway-core/src/wire/pong.rs                                        109                 2    98.17%           8                 0   100.00%          72                 0   100.00%           0                 0         -
lightway-core/src/wire/server_config.rs                                69                 2    97.10%           4                 0   100.00%          37                 0   100.00%           0                 0         -
lightway-expresslane/src/aead.rs                                       29                29     0.00%           2                 2     0.00%          23                23     0.00%           0                 0         -
lightway-expresslane/src/aead/pool.rs                                 127                71    44.09%           9                 4    55.56%          90                50    44.44%           0                 0         -
lightway-expresslane/src/key.rs                                        24                 0   100.00%           5                 0   100.00%          17                 0   100.00%           0                 0         -
lightway-expresslane/src/replay_window.rs                             269                 4    98.51%          20                 0   100.00%         174                 4    97.70%           0                 0         -
lightway-expresslane/src/session.rs                                   445               177    60.22%          19                 2    89.47%         270               105    61.11%           0                 0         -
lightway-expresslane/src/version.rs                                    32                 0   100.00%           4                 0   100.00%          25                 0   100.00%           0                 0         -
lightway-server/src/auth.rs                                           273                49    82.05%          22                 6    72.73%         171                28    83.63%           0                 0         -
lightway-server/src/config.rs                                         135                 0   100.00%           9                 0   100.00%         112                 0   100.00%           0                 0         -
lightway-server/src/connection.rs                                     137               137     0.00%          11                11     0.00%         110               110     0.00%           0                 0         -
lightway-server/src/connection_manager.rs                             346               346     0.00%          42                42     0.00%         303               303     0.00%           0                 0         -
lightway-server/src/connection_manager/connection_map.rs              407                20    95.09%          21                 1    95.24%         228                 8    96.49%           0                 0         -
lightway-server/src/io/inside.rs                                      100                21    79.00%          23                 9    60.87%          69                19    72.46%           0                 0         -
lightway-server/src/io/inside/tun.rs                                   61                61     0.00%          14                14     0.00%          45                45     0.00%           0                 0         -
lightway-server/src/io/outside/tcp.rs                                  93                93     0.00%          10                10     0.00%          68                68     0.00%           0                 0         -
lightway-server/src/io/outside/udp.rs                                 483               428    11.39%          27                24    11.11%         331               297    10.27%           0                 0         -
lightway-server/src/io/outside/udp/batch_receive.rs                   467                19    95.93%          20                 1    95.00%         265                15    94.34%           0                 0         -
lightway-server/src/io/outside/udp/cmsg.rs                            211                48    77.25%          17                 3    82.35%         174                43    75.29%           0                 0         -
lightway-server/src/io/outside/udp/send_queue.rs                      381                26    93.18%          24                 1    95.83%         209                16    92.34%           0                 0         -
lightway-server/src/ip_manager.rs                                     542                50    90.77%          22                 4    81.82%         242                23    90.50%           0                 0         -
lightway-server/src/ip_manager/ip_pool.rs                             545                 0   100.00%          28                 0   100.00%         257                 0   100.00%           0                 0         -
lightway-server/src/lib.rs                                            603               499    17.25%          34                26    23.53%         413               340    17.68%           0                 0         -
lightway-server/src/main.rs                                           201               201     0.00%          10                10     0.00%          96                96     0.00%           0                 0         -
lightway-server/src/metrics.rs                                        287               265     7.67%          99                89    10.10%         243               223     8.23%           0                 0         -
lightway-server/src/offload_stats.rs                                  125                74    40.80%           8                 3    62.50%          82                42    48.78%           0                 0         -
lightway-server/src/statistics.rs                                     133                59    55.64%           8                 4    50.00%          91                39    57.14%           0                 0         -
uniffi-bindgen/src/uniffi-bindgen.rs                                    3                 3     0.00%           1                 1     0.00%           3                 3     0.00%           0                 0         -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                                                               25802              7561    70.70%        1880               664    64.68%       15871              5218    67.12%           0                 0         -

✅ Region coverage 70% passes
✅ Line coverage 67% passes

@xv-thomas-leong
xv-thomas-leong force-pushed the main-tun-offload-fixes branch 3 times, most recently from d31d4c8 to 43f29ed Compare August 7, 2026 03:38
@xv-thomas-leong xv-thomas-leong changed the title TUN offload (1/3): pre-existing bug fixes Client TUN offload (1/3): pre-existing bug fixes Aug 7, 2026
@xv-thomas-leong
xv-thomas-leong marked this pull request as ready for review August 7, 2026 05:22
@xv-thomas-leong
xv-thomas-leong requested a review from a team as a code owner August 7, 2026 05:22

@kp-mariappan-ramasamy kp-mariappan-ramasamy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with minor nit!

Commits are using conventional commit format which we dont use in ligihtway repo.
Might be consistent to use module name as prefix as repo convention

…ader

Pre-existing bug on main, independent of any offload feature work.

When a TUN device negotiates `IFF_VNET_HDR` the kernel prepends a 10-byte
`virtio_net_hdr` to every read, so a read needs `mtu + 10` bytes of buffer
to carry a full-size packet. All three inside-path receive sites size
their buffer to `mtu` alone, so the tail of a full-size packet is lost.

The kernel does not report this. It copies what fits, returns that length,
and sets no flag the callers inspect, so the shortfall is silent.
Reproduced on Linux 6.17.0 x86_64 against a real TUN, interface MTU 1500,
inbound IP packet exactly 1500 bytes:

  buffer=1500  read=1500  ip_bytes=1490  total_length=1500   TRUNCATED
  buffer=1510  read=1510  ip_bytes=1500  total_length=1500   intact

Adds `Tun::vnet_headroom()`, returning `VIRTIO_NET_HDR_LEN` when the
device negotiated the flag and 0 otherwise, surfaced on the inside-IO
traits as a defaulted `vnet_headroom()` so both loops can size correctly
without knowing which backend they hold. The three sites become
`mtu + vnet_headroom()`:

  - `lightway-client/src/lib.rs`   inside_io_task
  - `lightway-server/src/lib.rs`   inside_io_loop
  - `TunDirect::recv_buf_many`     app-utils

Zero extra bytes unless offload is in use, and zero for the `IoUring`
backend, which reads into its own pooled buffers.

This is only half the story: with the header still not stripped on
receive, the packet handed to the parser continues to start with 10 bytes
of virtio header rather than the IP header. That is a separate defect in
the same path, fixed next. Sizing the buffer first means that fix needs no
caveat.
Pre-existing bug on main, independent of any offload feature work.

The two TUN directions decided whether virtio framing was in play by
consulting different things. `try_send` branches on `self.vnet_hdr`, a
property of the device. The receive side had no such check: `recv_buf`
truncated to the read length and never stripped the 10-byte header.
Stripping happened only in `recv_gso`, i.e. it was implied by *which
function the caller chose*, which in turn follows from a config flag
selecting an inside loop.

That leaves two independent sources of truth for one physical fact — does
this fd use vnet framing — reconciled only by a single one-directional
copy in `client()` that sets `tun_config.offload` from
`enable_tun_offload` and never clears it. `ClientConfig::tun_config`,
`TunConfig::offload` and `enable_tun_offload` are all public and
`connect()` is public, so a consumer can set the first without the last
and never execute that line: sends then work while every read hands the
parser 10 bytes of virtio header where the IP header should be.

`recv_buf` now branches on the same `self.vnet_hdr` bool, via a
`strip_vnet_hdr` helper mirroring `recv_gso` — a read no shorter than the
header is advanced past it, a shorter one is discarded and reported as
`WouldBlock` so the caller's loop retries instead of erroring. Both
directions now share one predicate, so a desynced config degrades to
"works without GSO batching" rather than corrupting traffic. The
non-offload path pays one bool test.

Verified against a real TUN on Linux 6.17.0 x86_64, interface MTU 1500,
inbound IP packet exactly 1500 bytes:

  raw read         : 1510 bytes (10 hdr + 1500 ip)
  handed to caller : 1500 bytes, first byte 0x45 (version 4)
  ip total_length  : 1500 -> matches, intact bare IP packet
  without this fix : parser saw first byte 0x01 (version 0)

`strip_vnet_hdr` also compares the IPv4 length field against the bytes
actually read. They disagree only if the buffer was not sized
`mtu + vnet_headroom()` and the kernel truncated the tail, which is
otherwise silent because the packet still looks well-formed. It warns
rather than drops: with `TUN_F_TSO*` enabled the kernel may also deliver
an aggregate here whose length field legitimately exceeds one MTU, and
dropping those would trade a diagnostic for data loss.

Also corrects the field doc, which said the header is 12 bytes. It is 10
(`size_of::<VirtioNetHdr>()`, matching the kernel's `TUNGETVNETHDRSZ`
default); 12 would be `virtio_net_hdr_mrg_rxbuf`, never negotiated here.

Known gap left open: the io-uring backend reads via `opcode::Read` on the
raw fd, bypassing `recv_buf` entirely, so it does not strip. That
combination is unreachable today — the client rejects offload with
io-uring in validation, and the server's `as_gso()` guard aborts startup
because `supports_gso()` is false for that backend — but it needs its own
fix before offload with io-uring is ever allowed.
Pre-existing bug on main, independent of any offload feature work.

A computed UDP checksum of zero was written to the wire as-is. RFC 768
requires it be transmitted as 0xFFFF.

Why zero occurs: the internet checksum is the one's complement of the
one's-complement sum, so the output is 0x0000 exactly when the folded sum
is 0xFFFF. One's-complement arithmetic has two representations of zero,
so landing on 0xFFFF is unremarkable -- roughly 1 in 65536 for content
uncorrelated with the addresses and length.

Why it matters more than that rate suggests: the sum is a deterministic
function of the 5-tuple, length and payload. A flow repeatedly sending the
same payload between the same endpoints produces the same checksum every
time, so if it is zero then every packet in that flow is broken for as
long as the pattern holds -- a permanent blackhole for one
keepalive/query shape while everything else works.

Impact by family. Over IPv6, 0x0000 is invalid (RFC 8200 s8.1) and the
receiver must discard the datagram. Over IPv4 it is the "sender computed
no checksum" sentinel, so the receiver skips verification and integrity
protection silently disappears on exactly the packets that failed to get
it. Note the kernel applies this substitution when it computes the
checksum itself, so taking `NEEDS_CSUM` packets over inherited the
obligation.

The substitution is free: 0xFFFF and 0x0000 are the same value in one's
complement, so no verifier can distinguish them.

`csum_start`/`csum_offset` alone cannot tell UDP from TCP, and blanket
substitution would be wrong because 0x0000 is a legal TCP checksum. So
`ip_l4_proto` reads the IPv4 protocol byte or the IPv6 next-header field
and the substitution applies only to protocol 17. For IPv6 carrying
extension headers the value is the first extension header's number rather
than the transport protocol, so the substitution is skipped -- the
behaviour before it existed. That direction is safe; it can never
mis-identify TCP as UDP, which is the only direction that corrupts.

The test derives the seed that makes the fold land on zero rather than
hard-coding a vector, so it cannot silently stop exercising the
substitution if the surrounding arithmetic changes. Mutation-verified:
removing the substitution fails exactly that test.

Also corrects the `MAX_GSO_SEGS` doc, which asserted `UDP_MAX_SEGMENTS`
*is* `1 << 6`. It is not fixed -- 64 before Linux 6.9, 128 from 6.9 onward
(raised in kernel commit 1382e3b6a350, backported to stable) -- and 64 is
pinned deliberately so a batch is accepted on both.
Pre-existing bug on main, independent of any offload feature work.

A superpacket with more than `MAX_GSO_SEGS` segments was dropped whole,
and the error was then swallowed upstream (`process_inside_packet` maps
`InvalidInsidePacket` to `continue`), so nothing surfaced. The inner TCP
flow retransmits into the same drop until congestion control backs off far
enough to build a smaller aggregate: sawtooth degradation on a path that
works fine with offload disabled.

Reachable with a sub-1024 MSS at a few hundred Mbps. The aggregate size is
`tcp_tso_autosize` -- roughly 1ms of data at the current pacing rate,
capped at 64KB -- not `65535 / MSS`, so it needs both a small MSS and a
high rate. At MSS 1350 the 64KB size cap yields 48 segments and the count
can never be reached at all.

The aggregate does not have to be dropped. The machinery already sends
correctly when no batch is open: `udp_send` passes straight through in
`Passthrough`, and the flush and reset are no-ops on an unopened buffer.
So the fix is to decide up front and simply not open the batch when the
segment count exceeds the cap:

    gso_fits_one_batch(gso_segs) -> bool

On the fallback leg each segment goes out via `send_to_outside` -- the
same call the non-offload path makes for an individual packet -- so the
aggregate still reaches the peer, just without wire batching. One `warn!`
plus a metric per skipped aggregate keeps the degradation visible.

`gso_dropped_iov_overflow` is replaced by `gso_batch_skipped`, because the
condition is no longer a drop and the old name would misreport it. Its doc
also described an `IOV_MAX`-derived cap, which was never what
`MAX_GSO_SEGS` bounds.

`gso_fits_one_batch` is a pure predicate specifically so the decision is
unit-testable without standing up a live wolfSSL connection; a boundary
test covers it, including the 122-segment small-MSS case.

Note the activity timestamp is updated on both legs -- it is deliberately
outside the `if batched` block, since a fallback send is still traffic.
Pre-existing bug on main, independent of any offload feature work.

`gso_type` in the virtio header is a bitfield, not an enum: Linux ORs
`VIRTIO_NET_HDR_GSO_ECN` (0x80) into it for ECN-marked flows, so an
ECN-marked TCPv4 aggregate arrives as 0x81. The server's inside GSO loop
compared it raw against `VIRTIO_NET_HDR_GSO_NONE`, which means an
ECN-marked single packet (0x80) fails the comparison and is misclassified
as an aggregate -- routed to `inside_data_received_gso` instead of
`inside_data_received`.

`gso.rs`'s own `is_tcp()` already masked the bit before comparing, so the
codebase knew the flag shares that field; this call site did not.

Adds `VirtioNetHdr::is_gso_none()` next to `is_tcp()` and routes the
comparison through it. Putting the mask on the type rather than at the
call site also keeps the ECN constant private to the module that owns it,
so callers in other crates never need to mirror a kernel ABI value.

In practice the kernel only sets ECN when `skb_is_gso()`, so a bare 0x80
should not occur -- but the two comparison styles for the same field were
an accident waiting to be inherited by the next call site, and there are
more of those coming.
@xv-thomas-leong
xv-thomas-leong merged commit 4fc00e5 into main Aug 17, 2026
152 of 160 checks passed
@xv-thomas-leong
xv-thomas-leong deleted the main-tun-offload-fixes branch August 17, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants