* [PATCH net-next v9 0/9] BIG TCP for UDP tunnels
@ 2026-07-10 13:42 Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide Alice Mikityanska
` (9 more replies)
0 siblings, 10 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
This series is a follow-up to "BIG TCP without HBH in IPv6", and it adds
support for BIG TCP IPv4/IPv6 workloads in vxlan and geneve. Now that
IPv6 BIG TCP doesn't require stripping the HBH in all various
combinations in tunneled traffic, adding BIG TCP becomes feasible.
Patch 01 adds accessors for the length field in the UDP header, as
suggested by Paolo in review. The usage of udp_set_len is then added in
the following patches that start using length=0 in BIG TCP UDP packets.
Patches 02-04 close the gaps that prevent BIG TCP packets from going
through UDP tunnel code.
Patch 05 validates packets in udp_gro_receive to exclude packets with
length=0 from GRO aggregation.
Patch 06 is for proper formatting in tcpdump (set UDP len to 0 rather
than a trimmed value on overflow).
Patches 07-08 bump up tso_max_size for VXLAN and GENEVE.
Patch 09 adds selftests.
Thanks all!
v9 changes: Converted the selftest to iptables counters to avoid the
issue with tcpdump pcaps taking all space in /tmp.
v8: https://lore.kernel.org/netdev/20260706181941.385672-1-alice.kernel@fastmail.im/
v8 changes: Addressed Paolo's and Jason's review comments. Made the
selftest more robust, added checks for SACK and mode with disabled tx
checksum offload on lower veth netdevs. Added details to commit
messages. Kept skb_segment logic unchanged, because the frags overflow
issue is not specific to BIG TCP.
v7: https://lore.kernel.org/netdev/20260611192955.604661-1-alice.kernel@fastmail.im/
v7 changes: Addressed Paolo's comments to properly block malformed
packets with UDP length=0 at udp_rcv level.
v6: https://lore.kernel.org/netdev/20260602093931.516281-1-alice.kernel@fastmail.im/
v6 changes: Lowered the packets threshold in the selftest to pass
upstream CI on debug kernels, also made it configurable.
v5: https://lore.kernel.org/netdev/20260526161200.1135899-1-alice.kernel@fastmail.im/
v5 changes: Rebased, dropped one of the patches that came in via the net
tree, addressed an overflow in nsim_do_psp found by Sashiko.
v4: https://lore.kernel.org/netdev/20260512165648.386518-1-alice.kernel@fastmail.im/
v4 changes: Rebased, addressed Sashiko AI review [1] and Willem's
comment about netperf flags.
My comments on Sashiko AI review per patch:
01: I'd prefer to keep the cases that I haven't tested outside of the
scope of this series, which is for VXLAN/GENEVE tunnels, not for ESP.
02: The patch doesn't have behavioral changes other than fixing the
checksum. The final uh->len assignment assigns the actual length, not
64k.
03: The check can't be loosened, because total_len is also assigned to
UDP length. BIG TCP works in the mode without GRO hint option.
04: Fixed the fallback value for udplen. BIG TCP is fine, it's the
uh->len = 0 case, uh->len can't exceed 64k.
05: In the BIG TCP case, partial GSO splits the SKB in two. If full
segmentation is needed, the SKB is split in many MSS-sized SKBs without
fragments.
06: Invalid packets from the wire are addressed in 08.
07: __udp_gso_segment only handles UDP GSO packets, which can't be
bigger than 64k. Kept udp_set_len_short in nf_nat_mangle_udp_packet, as
the function doesn't support BIG TCP packets anyway (see
mangle_contents).
08: udp_gro_receive handles packets before aggregation, there are no BIG
TCP packets at this point. RFC 768 doesn't say that padded UDP packets
are valid. Real jumbograms don't seem to be supported in this path
anyway.
09: The packet goes to skb_udp_tunnel_segment, not __udp_gso_segment.
__skb_udp_tunnel_segment handles this case.
12: Improved process cleanup by killing everything inside netns before
deleting them, and by avoiding killing netserver outside of netns.
netperf with -r in TCP_STREAM mode works, and the option has the
intended effect, but I replaced it with -m. Added dependency check for
tcpdump.
[1]: https://sashiko.dev/#/patchset/20260410150943.993350-1-alice.kernel%40fastmail.im
v3: https://lore.kernel.org/netdev/20260410150943.993350-1-alice.kernel@fastmail.im/
v3 changes: Fixed the redirect in the selftest, rebased over my L2TP fix
[2] for the syzbot report [3].
[2]: https://lore.kernel.org/netdev/20260403174949.843941-1-alice.kernel@fastmail.im/
[3]: https://lore.kernel.org/netdev/69a1dfba.050a0220.3a55be.0026.GAE@google.com/
v2: https://lore.kernel.org/netdev/20260226201600.222044-1-alice.kernel@fastmail.im/
v2 changes: Addressed the review comments: added UDP len helpers,
consolidated UDP len sanity checks in patch 08 into one, added
selftests. Added fixups to related code (patch 01-03).
v1: https://lore.kernel.org/netdev/20250923134742.1399800-1-maxtram95@gmail.com/
Alice Mikityanska (8):
net: Use helpers to get/set UDP len tree-wide
net: Enable BIG TCP with partial GSO
udp: Support BIG TCP GSO packets where they can occur
udp: Support gro_ipv4_max_size > 65536
udp: Validate UDP length in udp_gro_receive
udp: Set length in UDP header to 0 for big GSO packets
vxlan: Enable BIG TCP packets
selftests: net: Add a test for BIG TCP in UDP tunnels
Daniel Borkmann (1):
geneve: Enable BIG TCP packets
drivers/infiniband/core/lag.c | 2 +-
drivers/infiniband/sw/rxe/rxe_net.c | 4 +-
drivers/net/amt.c | 6 +-
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +-
drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +-
drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
.../marvell/octeontx2/nic/otx2_txrx.c | 2 +-
.../net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-
.../ethernet/mellanox/mlx5/core/en_selftest.c | 2 +-
drivers/net/ethernet/sfc/falcon/selftest.c | 4 +-
drivers/net/ethernet/sfc/selftest.c | 4 +-
drivers/net/ethernet/sfc/siena/selftest.c | 4 +-
drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +-
.../stmicro/stmmac/stmmac_selftests.c | 4 +-
drivers/net/geneve.c | 4 +-
drivers/net/netconsole.c | 2 +-
drivers/net/netdevsim/dev.c | 2 +-
drivers/net/netdevsim/psample.c | 2 +-
drivers/net/netdevsim/psp.c | 8 +-
drivers/net/vxlan/vxlan_core.c | 2 +
drivers/net/wireguard/receive.c | 2 +-
include/linux/udp.h | 27 +++
include/trace/events/icmp.h | 2 +-
lib/tests/blackhole_dev_kunit.c | 2 +-
net/6lowpan/nhc_udp.c | 10 +-
net/core/pktgen.c | 4 +-
net/core/selftests.c | 4 +-
net/core/skbuff.c | 10 +-
net/core/tso.c | 3 +-
net/ipv4/esp4.c | 2 +-
net/ipv4/fou_core.c | 2 +-
net/ipv4/ipconfig.c | 6 +-
net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 4 +-
net/ipv4/route.c | 2 +-
net/ipv4/udp.c | 7 +-
net/ipv4/udp_offload.c | 49 ++---
net/ipv4/udp_tunnel_core.c | 2 +-
net/ipv6/esp6.c | 5 +-
net/ipv6/fou6.c | 2 +-
net/ipv6/ip6_udp_tunnel.c | 2 +-
net/ipv6/udp.c | 7 +-
net/ipv6/udp_offload.c | 2 +-
net/l2tp/l2tp_core.c | 2 +-
net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
net/netfilter/nf_conntrack_proto_udp.c | 15 +-
net/netfilter/nf_log_syslog.c | 2 +-
net/netfilter/nf_nat_helper.c | 2 +-
net/psp/psp_main.c | 2 +-
net/sched/act_csum.c | 4 +-
net/xfrm/xfrm_nat_keepalive.c | 2 +-
tools/testing/selftests/net/Makefile | 1 +
.../testing/selftests/net/big_tcp_tunnels.sh | 188 ++++++++++++++++++
53 files changed, 340 insertions(+), 102 deletions(-)
create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
--
2.54.0
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-16 14:46 ` Simon Horman
2026-07-10 13:42 ` [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO Alice Mikityanska
` (8 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska, Jason A. Donenfeld
From: Alice Mikityanska <alice@isovalent.com>
Since BIG TCP for UDP tunnels will start using len=0 in the UDP header
as an indicator of a GSO packet bigger than 65535 bytes, this commit
introduces the following getter and setters to use tree-wide, in order
to explicitly mark places where len=0 may be expected, and handle them
properly:
1. udp_set_len() sets uh->len to its real value if it's not bigger than
65535, and to 0 otherwise: to be used in GSO context with aggregated
packets.
2. udp_set_len_short() is to be used when the length is known to fit 16
bits. It WARNs when the caller tries to assign a bigger value if
CONFIG_DEBUG_NET=y.
3. udp_get_len_short() returns len in host byte order: to be used on the
RX side to deal with non-aggregated packets, or to access the raw value
of the len field.
4. udp_get_len() decodes uh->len set by udp_set_len(). It checks whether
the packet is GSO to guard from malformed packets.
At the moment udp_set_len() is not used, a following commit will start
using it after enabling len>65535 for GSO.
Raw uh->len (in network byte order) is still accessed in a few places
for checksum calculation purposes, and to decode len=0 in udpv6_rcv for
jumbograms. udp_rcv and udpv6_rcv will be addressed by the commit that
starts using udp_set_len() to set UDP len=0 for BIG TCP packets in UDP
tunnels.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
drivers/infiniband/core/lag.c | 2 +-
drivers/infiniband/sw/rxe/rxe_net.c | 4 +-
drivers/net/amt.c | 6 +--
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +-
drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +-
drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
.../marvell/octeontx2/nic/otx2_txrx.c | 2 +-
.../net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-
.../ethernet/mellanox/mlx5/core/en_selftest.c | 2 +-
drivers/net/ethernet/sfc/falcon/selftest.c | 4 +-
drivers/net/ethernet/sfc/selftest.c | 4 +-
drivers/net/ethernet/sfc/siena/selftest.c | 4 +-
drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +-
.../stmicro/stmmac/stmmac_selftests.c | 4 +-
drivers/net/geneve.c | 2 +-
drivers/net/netconsole.c | 2 +-
drivers/net/netdevsim/dev.c | 2 +-
drivers/net/netdevsim/psample.c | 2 +-
drivers/net/netdevsim/psp.c | 8 ++--
drivers/net/wireguard/receive.c | 2 +-
include/linux/udp.h | 27 ++++++++++++++
include/trace/events/icmp.h | 2 +-
lib/tests/blackhole_dev_kunit.c | 2 +-
net/6lowpan/nhc_udp.c | 10 ++---
net/core/pktgen.c | 4 +-
net/core/selftests.c | 4 +-
net/core/tso.c | 3 +-
net/ipv4/esp4.c | 2 +-
net/ipv4/fou_core.c | 2 +-
net/ipv4/ipconfig.c | 6 +--
net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 4 +-
net/ipv4/route.c | 2 +-
net/ipv4/udp.c | 3 +-
net/ipv4/udp_offload.c | 37 +++++++++----------
net/ipv4/udp_tunnel_core.c | 2 +-
net/ipv6/esp6.c | 5 ++-
net/ipv6/fou6.c | 2 +-
net/ipv6/ip6_udp_tunnel.c | 2 +-
net/ipv6/udp.c | 3 +-
net/ipv6/udp_offload.c | 2 +-
net/l2tp/l2tp_core.c | 2 +-
net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
net/netfilter/nf_conntrack_proto_udp.c | 15 +++++++-
net/netfilter/nf_log_syslog.c | 2 +-
net/netfilter/nf_nat_helper.c | 2 +-
net/psp/psp_main.c | 2 +-
net/sched/act_csum.c | 4 +-
net/xfrm/xfrm_nat_keepalive.c | 2 +-
49 files changed, 131 insertions(+), 88 deletions(-)
diff --git a/drivers/infiniband/core/lag.c b/drivers/infiniband/core/lag.c
index 8fd80adfe833..00fe241737ff 100644
--- a/drivers/infiniband/core/lag.c
+++ b/drivers/infiniband/core/lag.c
@@ -36,7 +36,7 @@ static struct sk_buff *rdma_build_skb(struct net_device *netdev,
uh->source =
htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label));
uh->dest = htons(ROCE_V2_UDP_DPORT);
- uh->len = htons(sizeof(struct udphdr));
+ udp_set_len_short(uh, sizeof(struct udphdr));
if (is_ipv4) {
skb_push(skb, sizeof(struct iphdr));
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index 3741b2c4b0bb..53daaf4c1eb2 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -242,7 +242,7 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
pkt->port_num = 1;
pkt->hdr = (u8 *)(udph + 1);
pkt->mask = RXE_GRH_MASK;
- pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
+ pkt->paylen = udp_get_len_short(udph) - sizeof(*udph);
/* remove udp header */
skb_pull(skb, sizeof(struct udphdr));
@@ -305,7 +305,7 @@ static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port,
udph->dest = dst_port;
udph->source = src_port;
- udph->len = htons(skb->len);
+ udp_set_len_short(udph, skb->len);
udph->check = 0;
}
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 02168862f676..f8169c5512a5 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -667,7 +667,7 @@ static void amt_send_discovery(struct amt_dev *amt)
udph = udp_hdr(skb);
udph->source = amt->gw_port;
udph->dest = amt->relay_port;
- udph->len = htons(sizeof(*udph) + sizeof(*amtd));
+ udp_set_len_short(udph, sizeof(*udph) + sizeof(*amtd));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
@@ -760,7 +760,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
udph = udp_hdr(skb);
udph->source = amt->gw_port;
udph->dest = amt->relay_port;
- udph->len = htons(sizeof(*amtrh) + sizeof(*udph));
+ udp_set_len_short(udph, sizeof(*amtrh) + sizeof(*udph));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
@@ -2611,7 +2611,7 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
udph = udp_hdr(skb);
udph->source = amt->relay_port;
udph->dest = dport;
- udph->len = htons(sizeof(*amta) + sizeof(*udph));
+ udp_set_len_short(udph, sizeof(*amta) + sizeof(*udph));
udph->check = 0;
offset = skb_transport_offset(skb);
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 894f2d06d39d..ef5e657816f0 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -3129,7 +3129,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index 363c42bf3dcf..c30abf17cf5d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -1774,7 +1774,7 @@ static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len,
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 4ca1a0602307..fdea2758adf1 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1893,7 +1893,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
SKB_GSO_UDP_TUNNEL_CSUM)) {
if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
- l4.udp->len = 0;
+ udp_set_len_short(l4.udp, 0);
/* determine offset of outer transport header */
l4_start = (u8)(l4.hdr - skb->data);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 7f9056404f64..566b08ca3a6c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2871,7 +2871,7 @@ int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off)
(__force __wsum)htonl(paylen));
/* compute length of segmentation header */
off->tso_hdr_len = sizeof(struct udphdr) + l4_start;
- l4.udp->len = htons(shinfo->gso_size + sizeof(struct udphdr));
+ udp_set_len_short(l4.udp, shinfo->gso_size + sizeof(struct udphdr));
break;
default:
return -EINVAL;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 625bb5a05344..8d2d607bc92f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -750,7 +750,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
ext->lso_format = pfvf->hw.lso_udpv6_idx;
}
- udph->len = htons(sizeof(struct udphdr));
+ udp_set_len_short(udph, sizeof(struct udphdr));
}
} else if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
ext->tstmp = 1;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 6fbc0441c4b8..04af54b704d8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1081,7 +1081,7 @@ static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *
struct udphdr *uh;
uh = (struct udphdr *)(skb->data + udp_off);
- uh->len = htons(skb->len - udp_off);
+ udp_set_len_short(uh, skb->len - udp_off);
if (uh->check)
uh->check = ~udp_v4_check(skb->len - udp_off, ipv4->saddr,
@@ -1100,7 +1100,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr
struct udphdr *uh;
uh = (struct udphdr *)(skb->data + udp_off);
- uh->len = htons(skb->len - udp_off);
+ udp_set_len_short(uh, skb->len - udp_off);
if (uh->check)
uh->check = ~udp_v6_check(skb->len - udp_off, &ipv6->saddr,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
index accc26d1a872..1dcdb86690bb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
@@ -113,7 +113,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
/* Fill UDP header */
udph->source = htons(9);
udph->dest = htons(9); /* Discard Protocol */
- udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
+ udp_set_len_short(udph, sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
udph->check = 0;
/* Fill IP header */
diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c
index db4dd7fb77f5..4d29e0baf2eb 100644
--- a/drivers/net/ethernet/sfc/falcon/selftest.c
+++ b/drivers/net/ethernet/sfc/falcon/selftest.c
@@ -401,8 +401,8 @@ static void ef4_iterate_state(struct ef4_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
- payload->udp.len = htons(sizeof(*payload) -
- offsetof(struct ef4_loopback_payload, udp));
+ udp_set_len_short(&payload->udp, sizeof(*payload) -
+ offsetof(struct ef4_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 8ec76329237a..dc716feb79cb 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -398,8 +398,8 @@ static void efx_iterate_state(struct efx_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
- payload->udp.len = htons(sizeof(*payload) -
- offsetof(struct efx_loopback_payload, udp));
+ udp_set_len_short(&payload->udp, sizeof(*payload) -
+ offsetof(struct efx_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */
diff --git a/drivers/net/ethernet/sfc/siena/selftest.c b/drivers/net/ethernet/sfc/siena/selftest.c
index 930643612df5..c74cf5131364 100644
--- a/drivers/net/ethernet/sfc/siena/selftest.c
+++ b/drivers/net/ethernet/sfc/siena/selftest.c
@@ -399,8 +399,8 @@ static void efx_iterate_state(struct efx_nic *efx)
/* Initialise udp header */
payload->udp.source = 0;
- payload->udp.len = htons(sizeof(*payload) -
- offsetof(struct efx_loopback_payload, udp));
+ udp_set_len_short(&payload->udp, sizeof(*payload) -
+ offsetof(struct efx_loopback_payload, udp));
payload->udp.check = 0; /* checksum ignored */
/* Fill out payload */
diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c
index db222abef53b..c2ad3a358d20 100644
--- a/drivers/net/ethernet/sfc/tc_encap_actions.c
+++ b/drivers/net/ethernet/sfc/tc_encap_actions.c
@@ -311,7 +311,7 @@ static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len)
encap->encap_hdr_len += sizeof(*udp);
udp->dest = key->tp_dst;
- udp->len = cpu_to_be16(sizeof(*udp) + len);
+ udp_set_len_short(udp, sizeof(*udp) + len);
}
static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index a0c75886587c..29e824bd90ca 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -154,9 +154,9 @@ static struct sk_buff *stmmac_test_get_udp_skb(struct stmmac_priv *priv,
} else {
uhdr->source = htons(attr->sport);
uhdr->dest = htons(attr->dport);
- uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
+ udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size);
if (attr->max_size)
- uhdr->len = htons(attr->max_size -
+ udp_set_len_short(uhdr, attr->max_size -
(sizeof(*ihdr) + sizeof(*ehdr)));
uhdr->check = 0;
}
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 396e1a113cd4..011bf9d833ca 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -631,7 +631,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,
/* Adjust the nested UDP header len and checksum. */
uh = udp_hdr(skb);
- uh->len = htons(skb->len - gro_hint->nested_tp_offset);
+ udp_set_len_short(uh, skb->len - gro_hint->nested_tp_offset);
if (uh->check) {
len = skb->len - gro_hint->nested_tp_offset;
skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index c1812a98365b..a531548eb891 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -1792,7 +1792,7 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
udph = udp_hdr(skb);
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
- udph->len = htons(udp_len);
+ udp_set_len_short(udph, udp_len);
netpoll_udp_checksum(np, skb, len);
}
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index aed9ad5f1b43..f65b4cf4ea39 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -845,7 +845,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void)
udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
get_random_bytes(&udph->source, sizeof(u16));
get_random_bytes(&udph->dest, sizeof(u16));
- udph->len = htons(sizeof(struct udphdr) + data_len);
+ udp_set_len_short(udph, sizeof(struct udphdr) + data_len);
return skb;
}
diff --git a/drivers/net/netdevsim/psample.c b/drivers/net/netdevsim/psample.c
index 717d157c3ae2..1e71c3da4def 100644
--- a/drivers/net/netdevsim/psample.c
+++ b/drivers/net/netdevsim/psample.c
@@ -73,7 +73,7 @@ static struct sk_buff *nsim_dev_psample_skb_build(void)
udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
get_random_bytes(&udph->source, sizeof(u16));
get_random_bytes(&udph->dest, sizeof(u16));
- udph->len = htons(sizeof(struct udphdr) + data_len);
+ udp_set_len_short(udph, sizeof(struct udphdr) + data_len);
return skb;
}
diff --git a/drivers/net/netdevsim/psp.c b/drivers/net/netdevsim/psp.c
index 59c990fdc79e..6b3532b5e360 100644
--- a/drivers/net/netdevsim/psp.c
+++ b/drivers/net/netdevsim/psp.c
@@ -84,6 +84,7 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
struct iphdr *iph;
struct udphdr *uh;
__wsum csum;
+ int udplen;
/* Do not decapsulate. Receive the skb with the udp and psp
* headers still there as if this is a normal udp packet.
@@ -91,19 +92,20 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
* provide a valid checksum here, so the skb isn't dropped.
*/
uh = udp_hdr(skb);
+ udplen = udp_get_len(skb, uh, skb_transport_offset(skb));
csum = skb_checksum(skb, skb_transport_offset(skb),
- ntohs(uh->len), 0);
+ udplen, 0);
switch (skb->protocol) {
case htons(ETH_P_IP):
iph = ip_hdr(skb);
- uh->check = udp_v4_check(ntohs(uh->len), iph->saddr,
+ uh->check = udp_v4_check(udplen, iph->saddr,
iph->daddr, csum);
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
ip6h = ipv6_hdr(skb);
- uh->check = udp_v6_check(ntohs(uh->len), &ip6h->saddr,
+ uh->check = udp_v6_check(udplen, &ip6h->saddr,
&ip6h->daddr, csum);
break;
#endif
diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c
index eb8851113654..824bbefce61c 100644
--- a/drivers/net/wireguard/receive.c
+++ b/drivers/net/wireguard/receive.c
@@ -62,7 +62,7 @@ static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg)
* to have UDP fields.
*/
return -EINVAL;
- data_len = ntohs(udp->len);
+ data_len = udp_get_len_short(udp);
if (unlikely(data_len < sizeof(struct udphdr) ||
data_len > skb->len - data_offset))
/* UDP packet is reporting too small of a size or lying about
diff --git a/include/linux/udp.h b/include/linux/udp.h
index ce56ebcee5cb..998906ec3b32 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -23,6 +23,33 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
return (struct udphdr *)skb_transport_header(skb);
}
+static inline unsigned int udp_get_len(const struct sk_buff *skb,
+ const struct udphdr *uh,
+ unsigned int dataoff)
+{
+ if (uh->len)
+ return ntohs(uh->len);
+ if (skb_is_gso(skb)) /* BIG TCP */
+ return skb->len - dataoff;
+ return 0;
+}
+
+static inline unsigned int udp_get_len_short(const struct udphdr *uh)
+{
+ return ntohs(uh->len);
+}
+
+static inline void udp_set_len(struct udphdr *uh, unsigned int len)
+{
+ uh->len = len < GRO_LEGACY_MAX_SIZE ? htons(len) : 0;
+}
+
+static inline void udp_set_len_short(struct udphdr *uh, unsigned int len)
+{
+ DEBUG_NET_WARN_ON_ONCE(len >= GRO_LEGACY_MAX_SIZE);
+ uh->len = htons(len);
+}
+
#define UDP_HTABLE_SIZE_MIN_PERNET 128
#define UDP_HTABLE_SIZE_MIN (IS_ENABLED(CONFIG_BASE_SMALL) ? 128 : 256)
#define UDP_HTABLE_SIZE_MAX 65536
diff --git a/include/trace/events/icmp.h b/include/trace/events/icmp.h
index 31559796949a..09ae115099df 100644
--- a/include/trace/events/icmp.h
+++ b/include/trace/events/icmp.h
@@ -44,7 +44,7 @@ TRACE_EVENT(icmp_send,
} else {
__entry->sport = ntohs(uh->source);
__entry->dport = ntohs(uh->dest);
- __entry->ulen = ntohs(uh->len);
+ __entry->ulen = udp_get_len_short(uh);
}
p32 = (__be32 *) __entry->saddr;
diff --git a/lib/tests/blackhole_dev_kunit.c b/lib/tests/blackhole_dev_kunit.c
index 06834ab35f43..fa3e0533038d 100644
--- a/lib/tests/blackhole_dev_kunit.c
+++ b/lib/tests/blackhole_dev_kunit.c
@@ -46,7 +46,7 @@ static void test_blackholedev(struct kunit *test)
uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr));
skb_set_transport_header(skb, 0);
uh->source = uh->dest = htons(UDP_PORT);
- uh->len = htons(data_len);
+ udp_set_len_short(uh, data_len);
uh->check = 0;
/* (Network) IPv6 */
ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));
diff --git a/net/6lowpan/nhc_udp.c b/net/6lowpan/nhc_udp.c
index 0a506c77283d..ed4227e6db74 100644
--- a/net/6lowpan/nhc_udp.c
+++ b/net/6lowpan/nhc_udp.c
@@ -88,16 +88,16 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed)
switch (lowpan_dev(skb->dev)->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_802154_cb(skb)->d_size)
- uh.len = htons(lowpan_802154_cb(skb)->d_size -
- sizeof(struct ipv6hdr));
+ udp_set_len_short(&uh, lowpan_802154_cb(skb)->d_size -
+ sizeof(struct ipv6hdr));
else
- uh.len = htons(skb->len + sizeof(struct udphdr));
+ udp_set_len_short(&uh, skb->len + sizeof(struct udphdr));
break;
default:
- uh.len = htons(skb->len + sizeof(struct udphdr));
+ udp_set_len_short(&uh, skb->len + sizeof(struct udphdr));
break;
}
- pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
+ pr_debug("uncompressed UDP length: src = %d", udp_get_len_short(&uh));
/* replace the compressed UDP head by the uncompressed UDP
* header
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8e185b318288..5b4dd04d6124 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3005,7 +3005,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
udph->source = htons(pkt_dev->cur_udp_src);
udph->dest = htons(pkt_dev->cur_udp_dst);
- udph->len = htons(datalen + 8); /* DATA + udphdr */
+ udp_set_len_short(udph, datalen + 8); /* DATA + udphdr */
udph->check = 0;
iph->ihl = 5;
@@ -3138,7 +3138,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
udplen = datalen + sizeof(struct udphdr);
udph->source = htons(pkt_dev->cur_udp_src);
udph->dest = htons(pkt_dev->cur_udp_dst);
- udph->len = htons(udplen);
+ udp_set_len_short(udph, udplen);
udph->check = 0;
*(__be32 *) iph = htonl(0x60000000); /* Version + flow */
diff --git a/net/core/selftests.c b/net/core/selftests.c
index 0a203d3fb9dc..36b949ae520b 100644
--- a/net/core/selftests.c
+++ b/net/core/selftests.c
@@ -72,9 +72,9 @@ struct sk_buff *net_test_get_skb(struct net_device *ndev, u8 id,
} else {
uhdr->source = htons(attr->sport);
uhdr->dest = htons(attr->dport);
- uhdr->len = htons(sizeof(*shdr) + sizeof(*uhdr) + attr->size);
+ udp_set_len_short(uhdr, sizeof(*shdr) + sizeof(*uhdr) + attr->size);
if (attr->max_size)
- uhdr->len = htons(attr->max_size -
+ udp_set_len_short(uhdr, attr->max_size -
(sizeof(*ihdr) + sizeof(*ehdr)));
uhdr->check = 0;
}
diff --git a/net/core/tso.c b/net/core/tso.c
index 347b3856ddb9..d2934bcfa795 100644
--- a/net/core/tso.c
+++ b/net/core/tso.c
@@ -39,7 +39,8 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
} else {
struct udphdr *uh = (struct udphdr *)hdr;
- uh->len = htons(sizeof(*uh) + size);
+ /* size is after segmentation. */
+ udp_set_len_short(uh, sizeof(*uh) + size);
}
}
EXPORT_SYMBOL(tso_build_hdr);
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index dfc81ee969ae..a6c18aea7498 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -323,7 +323,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
uh = (struct udphdr *)esp->esph;
uh->source = sport;
uh->dest = dport;
- uh->len = htons(len);
+ udp_set_len_short(uh, len);
uh->check = 0;
/* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload
diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c
index 865bd7205122..a50740d0f288 100644
--- a/net/ipv4/fou_core.c
+++ b/net/ipv4/fou_core.c
@@ -1040,7 +1040,7 @@ static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
- uh->len = htons(skb->len);
+ udp_set_len_short(uh, skb->len);
udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
fl4->saddr, fl4->daddr, skb->len);
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index a35ffedacc7c..155db067eaec 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -847,7 +847,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
/* Construct UDP header */
b->udph.source = htons(68);
b->udph.dest = htons(67);
- b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
+ udp_set_len_short(&b->udph, sizeof(struct bootp_pkt) - sizeof(struct iphdr));
/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
/* Construct DHCP/BOOTP header */
@@ -1025,10 +1025,10 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
if (b->udph.source != htons(67) || b->udph.dest != htons(68))
goto drop;
- if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
+ if (ntohs(h->tot_len) < udp_get_len_short(&b->udph) + sizeof(struct iphdr))
goto drop;
- len = ntohs(b->udph.len) - sizeof(struct udphdr);
+ len = udp_get_len_short(&b->udph) - sizeof(struct udphdr);
ext_len = len - (sizeof(*b) -
sizeof(struct iphdr) -
sizeof(struct udphdr) -
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
index e540b86bd15b..4492bc548a66 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
@@ -127,7 +127,7 @@ static int snmp_translate(struct nf_conn *ct, int dir, struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
- u16 datalen = ntohs(udph->len) - sizeof(struct udphdr);
+ u16 datalen = udp_get_len_short(udph) - sizeof(struct udphdr);
char *data = (unsigned char *)udph + sizeof(struct udphdr);
struct snmp_ctx ctx;
int ret;
@@ -181,7 +181,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
* enough room for a UDP header. Just verify the UDP length field so we
* can mess around with the payload.
*/
- if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) {
+ if (udp_get_len_short(udph) != skb->len - (iph->ihl << 2)) {
nf_ct_helper_log(skb, ct, "dropping malformed packet\n");
return NF_DROP;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 3f3de5164d6e..0825ed983714 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3187,7 +3187,7 @@ static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst,
udph = skb_put_zero(skb, sizeof(struct udphdr));
udph->source = sport;
udph->dest = dport;
- udph->len = htons(sizeof(struct udphdr));
+ udp_set_len_short(udph, sizeof(struct udphdr));
udph->check = 0;
break;
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 59248a59358c..cb86124fd963 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1108,7 +1108,8 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
uh = udp_hdr(skb);
uh->source = inet_sk(sk)->inet_sport;
uh->dest = fl4->fl4_dport;
- uh->len = htons(len);
+ /* Datagram length checked in udp_sendmsg. */
+ udp_set_len_short(uh, len);
uh->check = 0;
if (cork->gso_size) {
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 29651b1a0bc7..493e2b9e16fb 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -279,11 +279,11 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
* segment instead of the entire frame.
*/
if (gso_partial && skb_is_gso(skb)) {
- uh->len = htons(skb_shinfo(skb)->gso_size +
- SKB_GSO_CB(skb)->data_offset +
- skb->head - (unsigned char *)uh);
+ udp_set_len_short(uh, skb_shinfo(skb)->gso_size +
+ SKB_GSO_CB(skb)->data_offset +
+ skb->head - (unsigned char *)uh);
} else {
- uh->len = htons(len);
+ udp_set_len_short(uh, len);
}
if (!need_csum)
@@ -468,7 +468,7 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
if (IS_ERR(skb))
return skb;
- udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
+ udp_set_len_short(udp_hdr(skb), sizeof(struct udphdr) + mss);
if (is_ipv6)
return __udpv6_gso_segment_list_csum(skb);
@@ -486,8 +486,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
unsigned int mss;
bool copy_dtor;
__sum16 check;
- __be16 newlen;
int ret = 0;
+ u16 newlen;
mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
@@ -564,8 +564,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
(skb_shinfo(gso_skb)->tx_flags & SKBTX_ANY_TSTAMP);
/* compute checksum adjustment based on old length versus new */
- newlen = htons(sizeof(*uh) + mss);
- check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
+ newlen = sizeof(*uh) + mss;
+ check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
for (;;) {
if (copy_dtor) {
@@ -577,7 +577,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
if (!seg->next)
break;
- uh->len = newlen;
+ udp_set_len_short(uh, newlen);
uh->check = check;
if (seg->ip_summed == CHECKSUM_PARTIAL)
@@ -594,11 +594,10 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
* segment may not be full MSS, account for that in the checksum
*/
if (!skb_is_gso(seg))
- newlen = htons(skb_tail_pointer(seg) -
- skb_transport_header(seg) + seg->data_len);
- check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
+ newlen = skb_tail_pointer(seg) - skb_transport_header(seg) + seg->data_len;
+ check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
- uh->len = newlen;
+ udp_set_len_short(uh, newlen);
uh->check = check;
if (seg->ip_summed == CHECKSUM_PARTIAL)
@@ -709,7 +708,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
}
/* Do not deal with padded or malicious packets, sorry ! */
- ulen = ntohs(uh->len);
+ ulen = udp_get_len_short(uh);
if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb)) {
NAPI_GRO_CB(skb)->flush = 1;
return NULL;
@@ -742,7 +741,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
* On len mismatch merge the first packet shorter than gso_size,
* otherwise complete the GRO packet.
*/
- if (ulen > ntohs(uh2->len) || flush) {
+ if (ulen > udp_get_len_short(uh2) || flush) {
pp = p;
} else {
if (NAPI_GRO_CB(skb)->is_flist) {
@@ -765,7 +764,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
}
}
- if (ret || ulen != ntohs(uh2->len) ||
+ if (ret || ulen != udp_get_len_short(uh2) ||
NAPI_GRO_CB(p)->count >= UDP_GRO_CNT_MAX)
pp = p;
@@ -915,12 +914,12 @@ static int udp_gro_complete_segment(struct sk_buff *skb)
int udp_gro_complete(struct sk_buff *skb, int nhoff,
udp_lookup_t lookup)
{
- __be16 newlen = htons(skb->len - nhoff);
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
+ unsigned int newlen = skb->len - nhoff;
struct sock *sk;
int err;
- uh->len = newlen;
+ udp_set_len_short(uh, newlen);
sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
udp4_lib_lookup_skb, skb, uh->source, uh->dest);
@@ -957,7 +956,7 @@ INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
- uh->len = htons(skb->len - nhoff);
+ udp_set_len_short(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index 9ab3728f9630..0fccb38f074d 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
uh->dest = dst_port;
uh->source = src_port;
- uh->len = htons(skb->len);
+ udp_set_len_short(uh, skb->len);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 296b57926abb..72ec0d7d1120 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -230,7 +230,8 @@ static void esp_output_encap_csum(struct sk_buff *skb)
if (*skb_mac_header(skb) == IPPROTO_UDP) {
struct udphdr *uh = udp_hdr(skb);
struct ipv6hdr *ip6h = ipv6_hdr(skb);
- int len = ntohs(uh->len);
+ /* esp6_output_udp_encap limits len to U16_MAX. */
+ int len = udp_get_len_short(uh);
unsigned int offset = skb_transport_offset(skb);
__wsum csum = skb_checksum(skb, offset, skb->len - offset, 0);
@@ -358,7 +359,7 @@ static struct ip_esp_hdr *esp6_output_udp_encap(struct sk_buff *skb,
uh = (struct udphdr *)esp->esph;
uh->source = sport;
uh->dest = dport;
- uh->len = htons(len);
+ udp_set_len_short(uh, len);
uh->check = 0;
*skb_mac_header(skb) = IPPROTO_UDP;
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c
index 157765259e2f..588929409241 100644
--- a/net/ipv6/fou6.c
+++ b/net/ipv6/fou6.c
@@ -30,7 +30,7 @@ static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
- uh->len = htons(skb->len);
+ udp_set_len_short(uh, skb->len);
udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb,
&fl6->saddr, &fl6->daddr, skb->len);
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index 9adb5775487f..dcff7fb16ff6 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
uh->dest = dst_port;
uh->source = src_port;
- uh->len = htons(skb->len);
+ udp_set_len_short(uh, skb->len);
skb_dst_set(skb, dst);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 392e18b97045..8bbd55546b6e 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1369,7 +1369,8 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
uh = udp_hdr(skb);
uh->source = fl6->fl6_sport;
uh->dest = fl6->fl6_dport;
- uh->len = htons(len);
+ /* Datagram length checked in udpv6_sendmsg. */
+ udp_set_len_short(uh, len);
uh->check = 0;
if (cork->gso_size) {
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 778afc7453ce..c92cf5ee3e6a 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -171,7 +171,7 @@ int udp6_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
- uh->len = htons(skb->len - nhoff);
+ udp_set_len_short(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index f940914959b1..4712cc41881a 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1296,7 +1296,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
ret = NET_XMIT_DROP;
goto out_unlock;
}
- uh->len = htons(udp_len);
+ udp_set_len_short(uh, udp_len);
/* Calculate UDP checksum if configured to do so */
#if IS_ENABLED(CONFIG_IPV6)
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index ce542ed4b013..ae3ed2c00ec3 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -1100,7 +1100,7 @@ ipvs_gue_encap(struct net *net, struct sk_buff *skb,
dport = cp->dest->tun_port;
udph->dest = dport;
udph->source = sport;
- udph->len = htons(skb->len);
+ udp_set_len_short(udph, skb->len);
udph->check = 0;
*next_protocol = IPPROTO_UDP;
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index cc9b7e5e1935..8a5675983e7c 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -41,11 +41,22 @@ static void udp_error_log(const struct sk_buff *skb,
nf_l4proto_log_invalid(skb, state, IPPROTO_UDP, "%s", msg);
}
+static bool udp_validate_len(struct sk_buff *skb,
+ const struct udphdr *hdr,
+ unsigned int dataoff)
+{
+ unsigned int udplen = udp_get_len_short(hdr);
+ unsigned int skblen = skb->len - dataoff;
+
+ if (udplen > skblen || udplen < sizeof(*hdr))
+ return false;
+ return true;
+}
+
static bool udp_error(struct sk_buff *skb,
unsigned int dataoff,
const struct nf_hook_state *state)
{
- unsigned int udplen = skb->len - dataoff;
const struct udphdr *hdr;
struct udphdr _hdr;
@@ -57,7 +68,7 @@ static bool udp_error(struct sk_buff *skb,
}
/* Truncated/malformed packets */
- if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
+ if (!udp_validate_len(skb, hdr, dataoff)) {
udp_error_log(skb, state, "truncated/malformed packet");
return true;
}
diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c
index e37b09b3203b..71dff0eb672c 100644
--- a/net/netfilter/nf_log_syslog.c
+++ b/net/netfilter/nf_log_syslog.c
@@ -301,7 +301,7 @@ nf_log_dump_udp_header(struct nf_log_buf *m,
/* Max length: 20 "SPT=65535 DPT=65535 " */
nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ",
- ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
+ ntohs(uh->source), ntohs(uh->dest), udp_get_len_short(uh));
out:
return 0;
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index bf591e6af005..3853f41db499 100644
--- a/net/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -161,7 +161,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
/* update the length of the UDP packet */
datalen = skb->len - protoff;
- udph->len = htons(datalen);
+ udp_set_len_short(udph, datalen);
/* fix udp checksum if udp checksum was previously calculated */
if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 8b2f178e317c..90c7dc4e76a1 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -231,7 +231,7 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi,
uh->source = udp_flow_src_port(net, skb, 0, 0, false);
}
uh->check = 0;
- uh->len = htons(udp_len);
+ udp_set_len_short(uh, udp_len);
psph->nexthdr = IPPROTO_TCP;
psph->hdrlen = PSP_HDRLEN_NOOPT;
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 078d3a27130b..5fff52a8ca90 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -276,7 +276,7 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl,
return 0;
iph = ip_hdr(skb);
- ul = ntohs(udph->len);
+ ul = udp_get_len_short(udph);
if (udplite || udph->check) {
@@ -334,7 +334,7 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl,
return 0;
ip6h = ipv6_hdr(skb);
- ul = ntohs(udph->len);
+ ul = udp_get_len_short(udph);
udph->check = 0;
diff --git a/net/xfrm/xfrm_nat_keepalive.c b/net/xfrm/xfrm_nat_keepalive.c
index 458931062a04..906458f3d8c5 100644
--- a/net/xfrm/xfrm_nat_keepalive.c
+++ b/net/xfrm/xfrm_nat_keepalive.c
@@ -133,7 +133,7 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
uh = skb_push(skb, sizeof(*uh));
uh->source = ka->encap_sport;
uh->dest = ka->encap_dport;
- uh->len = htons(skb->len);
+ udp_set_len_short(uh, skb->len);
uh->check = 0;
skb->mark = ka->smark;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-16 14:47 ` Simon Horman
2026-07-10 13:42 ` [PATCH net-next v9 3/9] udp: Support BIG TCP GSO packets where they can occur Alice Mikityanska
` (7 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
skb_segment is called for partial GSO, when netif_needs_gso returns true
in validate_xmit_skb. Partial GSO is needed, for example, when
segmentation of tunneled traffic is offloaded to a NIC that only
supports inner checksum offload.
Currently, skb_segment clamps the segment length to 65534 bytes, because
gso_size == 65535 is a special value GSO_BY_FRAGS, and we don't want
to accidentally assign mss = 65535, as it would fall into the
GSO_BY_FRAGS check further in the function.
This implementation, however, artificially blocks len > 65534, which is
possible since the introduction of BIG TCP. To allow bigger lengths and
avoid resegmentation of BIG TCP packets, store the gso_by_frags flag in
the beginning and don't use a special value of mss for this purpose
after mss was modified.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
net/core/skbuff.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 18dabb4e9cfa..6ae4c2b205f2 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4775,6 +4775,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
struct sk_buff *tail = NULL;
struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
unsigned int mss = skb_shinfo(head_skb)->gso_size;
+ bool gso_by_frags = mss == GSO_BY_FRAGS;
unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
unsigned int offset = doffset;
unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
@@ -4790,7 +4791,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
int nfrags, pos;
if ((skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY) &&
- mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) {
+ !gso_by_frags && mss != skb_headlen(head_skb)) {
struct sk_buff *check_skb;
for (check_skb = list_skb; check_skb; check_skb = check_skb->next) {
@@ -4818,7 +4819,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
sg = !!(features & NETIF_F_SG);
csum = !!can_checksum_protocol(features, proto);
- if (sg && csum && (mss != GSO_BY_FRAGS)) {
+ if (sg && csum && !gso_by_frags) {
if (!(features & NETIF_F_GSO_PARTIAL)) {
struct sk_buff *iter;
unsigned int frag_len;
@@ -4852,9 +4853,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
/* GSO partial only requires that we trim off any excess that
* doesn't fit into an MSS sized block, so take care of that
* now.
- * Cap len to not accidentally hit GSO_BY_FRAGS.
*/
- partial_segs = min(len, GSO_BY_FRAGS - 1) / mss;
+ partial_segs = len / mss;
if (partial_segs > 1)
mss *= partial_segs;
else
@@ -4878,7 +4878,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
int hsize;
int size;
- if (unlikely(mss == GSO_BY_FRAGS)) {
+ if (unlikely(gso_by_frags)) {
len = list_skb->len;
} else {
len = head_skb->len - offset;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 3/9] udp: Support BIG TCP GSO packets where they can occur
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 Alice Mikityanska
` (6 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
Wherever a GSO packet can occur, and its length is used to fill the UDP
header, use udp_set_len that assigns 0 if the length doesn't fit 16
bits, so that the packet can be properly parsed and segmented later,
instead of having truncated length.
Use udp_get_len in udp_validate_len to treat BIG TCP packets as valid.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
net/ipv4/fou_core.c | 2 +-
net/ipv6/fou6.c | 2 +-
net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
net/netfilter/nf_conntrack_proto_udp.c | 2 +-
net/psp/psp_main.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c
index a50740d0f288..aef3ce1dec7a 100644
--- a/net/ipv4/fou_core.c
+++ b/net/ipv4/fou_core.c
@@ -1040,7 +1040,7 @@ static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
- udp_set_len_short(uh, skb->len);
+ udp_set_len(uh, skb->len);
udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
fl4->saddr, fl4->daddr, skb->len);
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c
index 588929409241..4b659ca60ba9 100644
--- a/net/ipv6/fou6.c
+++ b/net/ipv6/fou6.c
@@ -30,7 +30,7 @@ static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
uh->dest = e->dport;
uh->source = sport;
- udp_set_len_short(uh, skb->len);
+ udp_set_len(uh, skb->len);
udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb,
&fl6->saddr, &fl6->daddr, skb->len);
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index ae3ed2c00ec3..c51ebd83a476 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -1100,7 +1100,7 @@ ipvs_gue_encap(struct net *net, struct sk_buff *skb,
dport = cp->dest->tun_port;
udph->dest = dport;
udph->source = sport;
- udp_set_len_short(udph, skb->len);
+ udp_set_len(udph, skb->len);
udph->check = 0;
*next_protocol = IPPROTO_UDP;
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 8a5675983e7c..a7edfefd6fd1 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -45,7 +45,7 @@ static bool udp_validate_len(struct sk_buff *skb,
const struct udphdr *hdr,
unsigned int dataoff)
{
- unsigned int udplen = udp_get_len_short(hdr);
+ unsigned int udplen = udp_get_len(skb, hdr, dataoff);
unsigned int skblen = skb->len - dataoff;
if (udplen > skblen || udplen < sizeof(*hdr))
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 90c7dc4e76a1..c9c1a8826b7f 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -231,7 +231,7 @@ static void psp_write_headers(struct net *net, struct sk_buff *skb, __be32 spi,
uh->source = udp_flow_src_port(net, skb, 0, 0, false);
}
uh->check = 0;
- udp_set_len_short(uh, udp_len);
+ udp_set_len(uh, udp_len);
psph->nexthdr = IPPROTO_TCP;
psph->hdrlen = PSP_HDRLEN_NOOPT;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (2 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 3/9] udp: Support BIG TCP GSO packets where they can occur Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-16 14:47 ` Simon Horman
2026-07-10 13:42 ` [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive Alice Mikityanska
` (5 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
Currently, gro_max_size and gro_ipv4_max_size can be set to values
bigger than 65536, and GRO will happily aggregate UDP to the configured
size (for example, with TCP traffic in VXLAN tunnels). However,
udp_gro_complete uses the 16-bit length field in the UDP header to store
the length of the aggregated packet. It leads to the packet truncation
later in udp_rcv.
Fix this by storing 0 to the UDP length field and by restoring the real
length from skb->len in udp_rcv. IP GRO already can store 0 to the IP
length field, and iph_totlen()/ipv6_payload_len() are capable of
restoring the real length, because the relevant packets (BIG TCP
tunneled in UDP tunnels) will have skb_is_gso_tcp == true.
Additionally, restrict handling uh->len=0 in udpv6_rcv to BIG TCP and
jumbograms only by using the udp_get_len helper.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
net/ipv4/udp.c | 4 ++--
net/ipv4/udp_offload.c | 4 ++--
net/ipv6/udp.c | 4 ++--
net/ipv6/udp_offload.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cb86124fd963..2b9b55a14758 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2592,8 +2592,8 @@ int udp_rcv(struct sk_buff *skb)
struct rtable *rt = skb_rtable(skb);
struct net *net = dev_net(skb->dev);
struct sock *sk = NULL;
- unsigned short ulen;
__be32 saddr, daddr;
+ unsigned int ulen;
struct udphdr *uh;
bool refcounted;
int drop_reason;
@@ -2607,7 +2607,7 @@ int udp_rcv(struct sk_buff *skb)
goto drop; /* No space for header. */
uh = udp_hdr(skb);
- ulen = ntohs(uh->len);
+ ulen = udp_get_len(skb, uh, 0);
saddr = ip_hdr(skb)->saddr;
daddr = ip_hdr(skb)->daddr;
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 493e2b9e16fb..4f9a3922937c 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -919,7 +919,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
struct sock *sk;
int err;
- udp_set_len_short(uh, newlen);
+ udp_set_len(uh, newlen);
sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
udp4_lib_lookup_skb, skb, uh->source, uh->dest);
@@ -956,7 +956,7 @@ INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
- udp_set_len_short(uh, skb->len - nhoff);
+ udp_set_len(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8bbd55546b6e..02272466f4c2 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1081,12 +1081,12 @@ INDIRECT_CALLABLE_SCOPE int udpv6_rcv(struct sk_buff *skb)
daddr = &ipv6_hdr(skb)->daddr;
uh = udp_hdr(skb);
- ulen = ntohs(uh->len);
+ ulen = udp_get_len(skb, uh, 0);
if (ulen > skb->len)
goto short_packet;
/* Check for jumbo payload */
- if (ulen == 0)
+ if (ulen == 0 && inet6_is_jumbogram(skb))
ulen = skb->len;
if (ulen < sizeof(*uh))
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index c92cf5ee3e6a..7370bcb80332 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -171,7 +171,7 @@ int udp6_gro_complete(struct sk_buff *skb, int nhoff)
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
if (NAPI_GRO_CB(skb)->is_flist && !NAPI_GRO_CB(skb)->encap_mark) {
- udp_set_len_short(uh, skb->len - nhoff);
+ udp_set_len(uh, skb->len - nhoff);
skb_shinfo(skb)->gso_type |= (SKB_GSO_FRAGLIST|SKB_GSO_UDP_L4);
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (3 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-16 14:48 ` Simon Horman
2026-07-10 13:42 ` [PATCH net-next v9 6/9] udp: Set length in UDP header to 0 for big GSO packets Alice Mikityanska
` (4 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
In the previous commit we started using uh->len = 0 as a marker of a GRO
packet bigger than 65536 bytes. Filter out malformed packets coming from
the wire with len=0 at udp_gro_receive to exclude them from GRO.
Note that a similar check was present in udp_gro_receive_segment, but
not in the UDP socket gro_receive flow. By adding an early check to
udp_gro_receive, the check in udp_gro_receive_segment can be dropped.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
net/ipv4/udp_offload.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 4f9a3922937c..8f77c8788f6d 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -707,12 +707,8 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
return NULL;
}
- /* Do not deal with padded or malicious packets, sorry ! */
ulen = udp_get_len_short(uh);
- if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb)) {
- NAPI_GRO_CB(skb)->flush = 1;
- return NULL;
- }
+
/* pull encapsulating udp header */
skb_gro_pull(skb, sizeof(struct udphdr));
@@ -782,8 +778,14 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
struct sk_buff *p;
struct udphdr *uh2;
unsigned int off = skb_gro_offset(skb);
+ unsigned int ulen;
int flush = 1;
+ /* Do not deal with padded or malicious packets, sorry! */
+ ulen = udp_get_len_short(uh);
+ if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb))
+ goto out;
+
/* We can do L4 aggregation only if the packet can't land in a tunnel
* otherwise we could corrupt the inner stream. Detecting such packets
* cannot be foolproof and the aggregation might still happen in some
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 6/9] udp: Set length in UDP header to 0 for big GSO packets
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (4 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 7/9] vxlan: Enable BIG TCP packets Alice Mikityanska
` (3 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
skb->len may be bigger than 65535 in UDP-based tunnels that have BIG TCP
enabled. If GSO aggregates packets that large, set the length in the UDP
header to 0, so that tcpdump can print such packets properly (treating
them as RFC 2675 jumbograms). Later in the pipeline, __udp_gso_segment
will set uh->len to the size of individual packets.
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
net/ipv4/udp_tunnel_core.c | 2 +-
net/ipv6/ip6_udp_tunnel.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index 0fccb38f074d..a128fe85620d 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
uh->dest = dst_port;
uh->source = src_port;
- udp_set_len_short(uh, skb->len);
+ udp_set_len(uh, skb->len);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index dcff7fb16ff6..32525a051a6f 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
uh->dest = dst_port;
uh->source = src_port;
- udp_set_len_short(uh, skb->len);
+ udp_set_len(uh, skb->len);
skb_dst_set(skb, dst);
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 7/9] vxlan: Enable BIG TCP packets
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (5 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 6/9] udp: Set length in UDP header to 0 for big GSO packets Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 8/9] geneve: " Alice Mikityanska
` (2 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
In Cilium we do support BIG TCP, but so far the latter has only been
enabled for direct routing use-cases. A lot of users rely on Cilium
with vxlan/geneve tunneling though. The underlying kernel infra for
tunneling has not been supporting BIG TCP up to this point.
Given we do now, bump tso_max_size for vxlan netdevs up to GSO_MAX_SIZE
to allow the admin to use BIG TCP with vxlan tunnels.
BIG TCP on vxlan disabled:
Standard MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 30.00 34440.00
8k MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
262144 32768 32768 30.00 55684.26
BIG TCP on vxlan enabled:
Standard MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 30.00 39564.78
8k MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
262144 32768 32768 30.00 61466.47
When tunnel offloads are not enabled/exposed and we fully need to rely on
SW-based segmentation on transmit (e.g. in case of Azure) then the more
aggressive batching also has a visible effect. Below example was on the
same setup as with above benchmarks but with HW support disabled:
# ethtool -k enp10s0f0np0 | grep udp
tx-udp_tnl-segmentation: off
tx-udp_tnl-csum-segmentation: off
tx-udp-segmentation: off
rx-udp_tunnel-port-offload: off
rx-udp-gro-forwarding: off
Before:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 60.00 21820.82
After:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 60.00 29390.78
Example receive side:
swapper 0 [002] 4712.645070: net:netif_receive_skb: dev=enp10s0f0np0 skbaddr=0xffff8f3b086e0200 len=129542
ffffffff8cfe3aaa __netif_receive_skb_core.constprop.0+0x6ca ([kernel.kallsyms])
ffffffff8cfe3aaa __netif_receive_skb_core.constprop.0+0x6ca ([kernel.kallsyms])
ffffffff8cfe47dd __netif_receive_skb_list_core+0xed ([kernel.kallsyms])
ffffffff8cfe4e52 netif_receive_skb_list_internal+0x1d2 ([kernel.kallsyms])
ffffffff8d0210d8 gro_complete.constprop.0+0x108 ([kernel.kallsyms])
ffffffff8d021724 dev_gro_receive+0x4e4 ([kernel.kallsyms])
ffffffff8d021a99 gro_receive_skb+0x89 ([kernel.kallsyms])
ffffffffc06edb71 mlx5e_handle_rx_cqe_mpwrq+0x131 ([kernel.kallsyms])
ffffffffc06ee38a mlx5e_poll_rx_cq+0x9a ([kernel.kallsyms])
ffffffffc06ef2c7 mlx5e_napi_poll+0x107 ([kernel.kallsyms])
ffffffff8cfe586d __napi_poll+0x2d ([kernel.kallsyms])
ffffffff8cfe5f8d net_rx_action+0x20d ([kernel.kallsyms])
ffffffff8c35d252 handle_softirqs+0xe2 ([kernel.kallsyms])
ffffffff8c35d556 __irq_exit_rcu+0xd6 ([kernel.kallsyms])
ffffffff8c35d81e irq_exit_rcu+0xe ([kernel.kallsyms])
ffffffff8d2602b8 common_interrupt+0x98 ([kernel.kallsyms])
ffffffff8c000da7 asm_common_interrupt+0x27 ([kernel.kallsyms])
ffffffff8d2645c5 cpuidle_enter_state+0xd5 ([kernel.kallsyms])
ffffffff8cf6358e cpuidle_enter+0x2e ([kernel.kallsyms])
ffffffff8c3ba932 call_cpuidle+0x22 ([kernel.kallsyms])
ffffffff8c3bfb5e do_idle+0x1ce ([kernel.kallsyms])
ffffffff8c3bfd79 cpu_startup_entry+0x29 ([kernel.kallsyms])
ffffffff8c30a6c2 start_secondary+0x112 ([kernel.kallsyms])
ffffffff8c2c142d common_startup_64+0x13e ([kernel.kallsyms])
Example transmit side:
swapper 0 [005] 4768.021375: net:net_dev_xmit: dev=enp10s0f0np0 skbaddr=0xffff8af32ebe1200 len=129556 rc=0
ffffffffa75e19c3 dev_hard_start_xmit+0x173 ([kernel.kallsyms])
ffffffffa75e19c3 dev_hard_start_xmit+0x173 ([kernel.kallsyms])
ffffffffa7653823 sch_direct_xmit+0x143 ([kernel.kallsyms])
ffffffffa75e2780 __dev_queue_xmit+0xc70 ([kernel.kallsyms])
ffffffffa76a1205 ip_finish_output2+0x265 ([kernel.kallsyms])
ffffffffa76a1577 __ip_finish_output+0x87 ([kernel.kallsyms])
ffffffffa76a165b ip_finish_output+0x2b ([kernel.kallsyms])
ffffffffa76a179e ip_output+0x5e ([kernel.kallsyms])
ffffffffa76a19d5 ip_local_out+0x35 ([kernel.kallsyms])
ffffffffa770d0e5 iptunnel_xmit+0x185 ([kernel.kallsyms])
ffffffffc179634e nf_nat_used_tuple_new.cold+0x1129 ([kernel.kallsyms])
ffffffffc17a7301 vxlan_xmit_one+0xc21 ([kernel.kallsyms])
ffffffffc17a80a2 vxlan_xmit+0x4a2 ([kernel.kallsyms])
ffffffffa75e18af dev_hard_start_xmit+0x5f ([kernel.kallsyms])
ffffffffa75e1d3f __dev_queue_xmit+0x22f ([kernel.kallsyms])
ffffffffa76a1205 ip_finish_output2+0x265 ([kernel.kallsyms])
ffffffffa76a1577 __ip_finish_output+0x87 ([kernel.kallsyms])
ffffffffa76a165b ip_finish_output+0x2b ([kernel.kallsyms])
ffffffffa76a179e ip_output+0x5e ([kernel.kallsyms])
ffffffffa76a1de2 __ip_queue_xmit+0x1b2 ([kernel.kallsyms])
ffffffffa76a2135 ip_queue_xmit+0x15 ([kernel.kallsyms])
ffffffffa76c70a2 __tcp_transmit_skb+0x522 ([kernel.kallsyms])
ffffffffa76c931a tcp_write_xmit+0x65a ([kernel.kallsyms])
ffffffffa76cb42e tcp_tsq_write+0x5e ([kernel.kallsyms])
ffffffffa76cb7ef tcp_tasklet_func+0x10f ([kernel.kallsyms])
ffffffffa695d9f7 tasklet_action_common+0x107 ([kernel.kallsyms])
ffffffffa695db99 tasklet_action+0x29 ([kernel.kallsyms])
ffffffffa695d252 handle_softirqs+0xe2 ([kernel.kallsyms])
ffffffffa695d556 __irq_exit_rcu+0xd6 ([kernel.kallsyms])
ffffffffa695d81e irq_exit_rcu+0xe ([kernel.kallsyms])
ffffffffa78602b8 common_interrupt+0x98 ([kernel.kallsyms])
ffffffffa6600da7 asm_common_interrupt+0x27 ([kernel.kallsyms])
ffffffffa78645c5 cpuidle_enter_state+0xd5 ([kernel.kallsyms])
ffffffffa756358e cpuidle_enter+0x2e ([kernel.kallsyms])
ffffffffa69ba932 call_cpuidle+0x22 ([kernel.kallsyms])
ffffffffa69bfb5e do_idle+0x1ce ([kernel.kallsyms])
ffffffffa69bfd79 cpu_startup_entry+0x29 ([kernel.kallsyms])
ffffffffa690a6c2 start_secondary+0x112 ([kernel.kallsyms])
ffffffffa68c142d common_startup_64+0x13e ([kernel.kallsyms])
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/vxlan/vxlan_core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 67c367cc5662..3a32f067e701 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -3370,6 +3370,8 @@ static void vxlan_setup(struct net_device *dev)
dev->mangleid_features = NETIF_F_GSO_PARTIAL;
netif_keep_dst(dev);
+ netif_set_tso_max_size(dev, GSO_MAX_SIZE);
+
dev->priv_flags |= IFF_NO_QUEUE;
dev->change_proto_down = true;
dev->lltx = true;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 8/9] geneve: Enable BIG TCP packets
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (6 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 7/9] vxlan: Enable BIG TCP packets Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-16 14:48 ` Simon Horman
2026-07-10 13:42 ` [PATCH net-next v9 9/9] selftests: net: Add a test for BIG TCP in UDP tunnels Alice Mikityanska
2026-07-15 6:11 ` zebang.li
9 siblings, 1 reply; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
From: Daniel Borkmann <daniel@iogearbox.net>
In Cilium we do support BIG TCP, but so far the latter has only been
enabled for direct routing use-cases. A lot of users rely on Cilium
with vxlan/geneve tunneling though. The underlying kernel infra for
tunneling has not been supporting BIG TCP up to this point.
Given we do now, bump tso_max_size for geneve netdevs up to GSO_MAX_SIZE
to allow the admin to use BIG TCP with geneve tunnels.
BIG TCP on geneve disabled:
Standard MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 30.00 37391.34
8k MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
262144 32768 32768 60.00 58030.19
BIG TCP on geneve enabled:
Standard MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 30.00 40891.57
8k MTU:
# netperf -H 10.1.0.2 -t TCP_STREAM -l60
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.1.0.2 () port 0 AF_INET : demo
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
262144 32768 32768 60.00 61458.39
Example receive side:
swapper 0 [008] 3682.509996: net:netif_receive_skb: dev=geneve0 skbaddr=0xffff8f3b0a781800 len=129492
ffffffff8cfe3aaa __netif_receive_skb_core.constprop.0+0x6ca ([kernel.kallsyms])
ffffffff8cfe3aaa __netif_receive_skb_core.constprop.0+0x6ca ([kernel.kallsyms])
ffffffff8cfe47dd __netif_receive_skb_list_core+0xed ([kernel.kallsyms])
ffffffff8cfe4e52 netif_receive_skb_list_internal+0x1d2 ([kernel.kallsyms])
ffffffff8cfe573c napi_complete_done+0x7c ([kernel.kallsyms])
ffffffff8d046c23 gro_cell_poll+0x83 ([kernel.kallsyms])
ffffffff8cfe586d __napi_poll+0x2d ([kernel.kallsyms])
ffffffff8cfe5f8d net_rx_action+0x20d ([kernel.kallsyms])
ffffffff8c35d252 handle_softirqs+0xe2 ([kernel.kallsyms])
ffffffff8c35d556 __irq_exit_rcu+0xd6 ([kernel.kallsyms])
ffffffff8c35d81e irq_exit_rcu+0xe ([kernel.kallsyms])
ffffffff8d2602b8 common_interrupt+0x98 ([kernel.kallsyms])
ffffffff8c000da7 asm_common_interrupt+0x27 ([kernel.kallsyms])
ffffffff8d2645c5 cpuidle_enter_state+0xd5 ([kernel.kallsyms])
ffffffff8cf6358e cpuidle_enter+0x2e ([kernel.kallsyms])
ffffffff8c3ba932 call_cpuidle+0x22 ([kernel.kallsyms])
ffffffff8c3bfb5e do_idle+0x1ce ([kernel.kallsyms])
ffffffff8c3bfd79 cpu_startup_entry+0x29 ([kernel.kallsyms])
ffffffff8c30a6c2 start_secondary+0x112 ([kernel.kallsyms])
ffffffff8c2c142d common_startup_64+0x13e ([kernel.kallsyms])
Example transmit side:
swapper 0 [002] 3403.688687: net:net_dev_xmit: dev=enp10s0f0np0 skbaddr=0xffff8af31d104ae8 len=129556 rc=0
ffffffffa75e19c3 dev_hard_start_xmit+0x173 ([kernel.kallsyms])
ffffffffa75e19c3 dev_hard_start_xmit+0x173 ([kernel.kallsyms])
ffffffffa7653823 sch_direct_xmit+0x143 ([kernel.kallsyms])
ffffffffa75e2780 __dev_queue_xmit+0xc70 ([kernel.kallsyms])
ffffffffa76a1205 ip_finish_output2+0x265 ([kernel.kallsyms])
ffffffffa76a1577 __ip_finish_output+0x87 ([kernel.kallsyms])
ffffffffa76a165b ip_finish_output+0x2b ([kernel.kallsyms])
ffffffffa76a179e ip_output+0x5e ([kernel.kallsyms])
ffffffffa76a19d5 ip_local_out+0x35 ([kernel.kallsyms])
ffffffffa770d0e5 iptunnel_xmit+0x185 ([kernel.kallsyms])
ffffffffc179634e nf_nat_used_tuple_new.cold+0x1129 ([kernel.kallsyms])
ffffffffc179d3e0 geneve_xmit+0x920 ([kernel.kallsyms])
ffffffffa75e18af dev_hard_start_xmit+0x5f ([kernel.kallsyms])
ffffffffa75e1d3f __dev_queue_xmit+0x22f ([kernel.kallsyms])
ffffffffa76a1205 ip_finish_output2+0x265 ([kernel.kallsyms])
ffffffffa76a1577 __ip_finish_output+0x87 ([kernel.kallsyms])
ffffffffa76a165b ip_finish_output+0x2b ([kernel.kallsyms])
ffffffffa76a179e ip_output+0x5e ([kernel.kallsyms])
ffffffffa76a1de2 __ip_queue_xmit+0x1b2 ([kernel.kallsyms])
ffffffffa76a2135 ip_queue_xmit+0x15 ([kernel.kallsyms])
ffffffffa76c70a2 __tcp_transmit_skb+0x522 ([kernel.kallsyms])
ffffffffa76c931a tcp_write_xmit+0x65a ([kernel.kallsyms])
ffffffffa76ca3b9 __tcp_push_pending_frames+0x39 ([kernel.kallsyms])
ffffffffa76c1fb6 tcp_rcv_established+0x276 ([kernel.kallsyms])
ffffffffa76d3957 tcp_v4_do_rcv+0x157 ([kernel.kallsyms])
ffffffffa76d6053 tcp_v4_rcv+0x1243 ([kernel.kallsyms])
ffffffffa769b8ea ip_protocol_deliver_rcu+0x2a ([kernel.kallsyms])
ffffffffa769bab7 ip_local_deliver_finish+0x77 ([kernel.kallsyms])
ffffffffa769bb4d ip_local_deliver+0x6d ([kernel.kallsyms])
ffffffffa769abe7 ip_sublist_rcv_finish+0x37 ([kernel.kallsyms])
ffffffffa769b713 ip_sublist_rcv+0x173 ([kernel.kallsyms])
ffffffffa769bde2 ip_list_rcv+0x102 ([kernel.kallsyms])
ffffffffa75e4868 __netif_receive_skb_list_core+0x178 ([kernel.kallsyms])
ffffffffa75e4e52 netif_receive_skb_list_internal+0x1d2 ([kernel.kallsyms])
ffffffffa75e573c napi_complete_done+0x7c ([kernel.kallsyms])
ffffffffa7646c23 gro_cell_poll+0x83 ([kernel.kallsyms])
ffffffffa75e586d __napi_poll+0x2d ([kernel.kallsyms])
ffffffffa75e5f8d net_rx_action+0x20d ([kernel.kallsyms])
ffffffffa695d252 handle_softirqs+0xe2 ([kernel.kallsyms])
ffffffffa695d556 __irq_exit_rcu+0xd6 ([kernel.kallsyms])
ffffffffa695d81e irq_exit_rcu+0xe ([kernel.kallsyms])
ffffffffa78602b8 common_interrupt+0x98 ([kernel.kallsyms])
ffffffffa6600da7 asm_common_interrupt+0x27 ([kernel.kallsyms])
ffffffffa78645c5 cpuidle_enter_state+0xd5 ([kernel.kallsyms])
ffffffffa756358e cpuidle_enter+0x2e ([kernel.kallsyms])
ffffffffa69ba932 call_cpuidle+0x22 ([kernel.kallsyms])
ffffffffa69bfb5e do_idle+0x1ce ([kernel.kallsyms])
ffffffffa69bfd79 cpu_startup_entry+0x29 ([kernel.kallsyms])
ffffffffa690a6c2 start_secondary+0x112 ([kernel.kallsyms])
ffffffffa68c142d common_startup_64+0x13e ([kernel.kallsyms])
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Co-developed-by: Alice Mikityanska <alice@isovalent.com>
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
---
drivers/net/geneve.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 011bf9d833ca..a1639ad53077 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1745,6 +1745,8 @@ static void geneve_setup(struct net_device *dev)
dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
netif_keep_dst(dev);
+ netif_set_tso_max_size(dev, GSO_MAX_SIZE);
+
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
dev->lltx = true;
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v9 9/9] selftests: net: Add a test for BIG TCP in UDP tunnels
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
` (7 preceding siblings ...)
2026-07-10 13:42 ` [PATCH net-next v9 8/9] geneve: " Alice Mikityanska
@ 2026-07-10 13:42 ` Alice Mikityanska
2026-07-15 6:11 ` zebang.li
9 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-10 13:42 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
From: Alice Mikityanska <alice@isovalent.com>
The test sets up VXLAN and GENEVE tunnels over IPv4 and IPv6 and runs
IPv4 and IPv6 traffic through them with BIG TCP enabled. It checks that
a non-negligible amount of big aggregated packets are seen by setting up
iptables counters.
Check the number of packets on both TX and RX sides to verify that GSO
packets are valid and not dropped. Capture on the lower netdev (veth),
when checksum offload is on, to verify that encapsulated BIG TCP packets
can get to their destination. In the test with TX checksum offload off,
software GSO splits aggregated VXLAN packets before passing them to
veth, so capture inside the tunnel instead to check that the big packets
are not dropped.
Check that the amount of SACKs is negligible. On unsupported kernels,
some amount of broken GSO packets bigger than 65536 bytes can be
produced in VXLAN tunnels, but they don't reach the destination. Seeing
TCP SACKs is a sign that such packets could have been dropped (in such
cases, the amount of SACKs is a few times bigger than the number of
attempts to send BIG TCP packets).
Signed-off-by: Alice Mikityanska <alice@isovalent.com>
---
tools/testing/selftests/net/Makefile | 1 +
.../testing/selftests/net/big_tcp_tunnels.sh | 188 ++++++++++++++++++
2 files changed, 189 insertions(+)
create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 708d960ae07d..4cb0a0bc1eea 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -13,6 +13,7 @@ TEST_PROGS := \
arp_ndisc_untracked_subnets.sh \
bareudp.sh \
big_tcp.sh \
+ big_tcp_tunnels.sh \
bind_bhash.sh \
bpf_offload.py \
bridge_stp_mode.sh \
diff --git a/tools/testing/selftests/net/big_tcp_tunnels.sh b/tools/testing/selftests/net/big_tcp_tunnels.sh
new file mode 100755
index 000000000000..d6513ed8d4e8
--- /dev/null
+++ b/tools/testing/selftests/net/big_tcp_tunnels.sh
@@ -0,0 +1,188 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Testing for IPv4 and IPv6 BIG TCP over VXLAN and GENEVE tunnels.
+
+SERVER_NS=$(mktemp -u server-XXXXXXXX)
+SERVER_IP4="192.168.1.1"
+SERVER_IP6="2001:db8::1:1"
+SERVER_IP4_TUN="192.168.2.1"
+SERVER_IP6_TUN="2001:db8::2:1"
+
+CLIENT_NS=$(mktemp -u client-XXXXXXXX)
+CLIENT_IP4="192.168.1.2"
+CLIENT_IP6="2001:db8::1:2"
+CLIENT_IP4_TUN="192.168.2.2"
+CLIENT_IP6_TUN="2001:db8::2:2"
+
+: "${PACKETS_THRESHOLD:=1000}"
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+setup() {
+ ip netns add "$SERVER_NS"
+ ip netns add "$CLIENT_NS"
+ ip -netns "$SERVER_NS" link add link1 type veth peer name link0 netns "$CLIENT_NS"
+
+ ip -netns "$CLIENT_NS" link set link0 up
+ ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4/24" dev link0
+ ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6/112" dev link0 nodad
+ ip -netns "$CLIENT_NS" link set link0 \
+ gso_max_size 196608 gso_ipv4_max_size 196608 \
+ gro_max_size 196608 gro_ipv4_max_size 196608
+ ip -netns "$SERVER_NS" link set link1 up
+ ip -netns "$SERVER_NS" addr replace "$SERVER_IP4/24" dev link1
+ ip -netns "$SERVER_NS" addr replace "$SERVER_IP6/112" dev link1 nodad
+ ip -netns "$SERVER_NS" link set link1 \
+ gso_max_size 196608 gso_ipv4_max_size 196608 \
+ gro_max_size 196608 gro_ipv4_max_size 196608
+
+ ip netns exec "$SERVER_NS" netserver >/dev/null
+}
+
+setup_tunnel() {
+ if [ "$2" = 4 ]; then
+ SERVER_IP="$SERVER_IP4"
+ CLIENT_IP="$CLIENT_IP4"
+ echo "Setting up ${1^^} over IPv4, veth tx csum offload $3"
+ else
+ SERVER_IP="$SERVER_IP6"
+ CLIENT_IP="$CLIENT_IP6"
+ echo "Setting up ${1^^} over IPv6, veth tx csum offload $3"
+ fi
+
+ if [ "$1" = vxlan ]; then
+ ip -netns "$CLIENT_NS" link add tun0 type vxlan \
+ id 5001 remote "$SERVER_IP" local "$CLIENT_IP" dev link0 dstport 4789
+ else
+ ip -netns "$CLIENT_NS" link add tun0 type geneve \
+ id 5001 remote "$SERVER_IP"
+ fi
+ ip -netns "$CLIENT_NS" link set tun0 up
+ ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4_TUN/24" dev tun0
+ ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6_TUN/112" dev tun0 nodad
+ ip -netns "$CLIENT_NS" link set tun0 \
+ gso_max_size 196608 gso_ipv4_max_size 196608 \
+ gro_max_size 196608 gro_ipv4_max_size 196608
+ if [ "$1" = vxlan ]; then
+ ip -netns "$SERVER_NS" link add tun1 type vxlan \
+ id 5001 remote "$CLIENT_IP" local "$SERVER_IP" dev link1 dstport 4789
+ else
+ ip -netns "$SERVER_NS" link add tun1 type geneve \
+ id 5001 remote "$CLIENT_IP"
+ fi
+ ip -netns "$SERVER_NS" link set tun1 up
+ ip -netns "$SERVER_NS" addr replace "$SERVER_IP4_TUN/24" dev tun1
+ ip -netns "$SERVER_NS" addr replace "$SERVER_IP6_TUN/112" dev tun1 nodad
+ ip -netns "$SERVER_NS" link set tun1 \
+ gso_max_size 196608 gso_ipv4_max_size 196608 \
+ gro_max_size 196608 gro_ipv4_max_size 196608
+
+ ip netns exec "$CLIENT_NS" ethtool -K link0 tx-checksumming "$3" > /dev/null
+ ip netns exec "$SERVER_NS" ethtool -K link1 tx-checksumming "$3" > /dev/null
+}
+
+cleanup_tunnel() {
+ ip -netns "$CLIENT_NS" link del tun0
+ ip -netns "$SERVER_NS" link del tun1
+}
+
+cleanup() {
+ ip netns pids "$SERVER_NS" | xargs -r kill
+ ip netns pids "$CLIENT_NS" | xargs -r kill
+ ip netns del "$SERVER_NS"
+ ip netns del "$CLIENT_NS"
+ rm -rf "$WORKDIR"
+}
+
+do_test() {
+ # When tx csum offload is off, software GSO is performed before passing the
+ # packet to veth. Check BIG TCP packets inside the VXLAN tunnel to verify
+ # the software checksum path: if the checksum code is broken, these packets
+ # will be dropped.
+ if [ "$3" = on ]; then
+ CAPTURE_IFACE='link'
+ if [ "$1" = 4 ]; then
+ IPTABLES=iptables
+ else
+ IPTABLES=ip6tables
+ fi
+ else
+ CAPTURE_IFACE='tun'
+ if [ "$2" = 4 ]; then
+ IPTABLES=iptables
+ else
+ IPTABLES=ip6tables
+ fi
+ fi
+ if [ "$2" = 4 ]; then
+ IPTABLES_SACK=iptables
+ else
+ IPTABLES_SACK=ip6tables
+ fi
+
+ ip netns exec "$SERVER_NS" "$IPTABLES" -w -t raw -I PREROUTING -i "${CAPTURE_IFACE}1" -m length ! --length 0:65535 -m comment --comment "bigtcp"
+ ip netns exec "$CLIENT_NS" "$IPTABLES" -w -t raw -I OUTPUT -o "${CAPTURE_IFACE}0" -m length ! --length 0:65535 -m comment --comment "bigtcp"
+ ip netns exec "$SERVER_NS" "$IPTABLES_SACK" -w -t raw -I OUTPUT -o "tun1" -p tcp -m tcp --tcp-flags ACK ACK --tcp-option 5 -m comment --comment "sack"
+
+ if [ "$2" = 4 ]; then
+ SERVER_IP="$SERVER_IP4_TUN"
+ echo "Running IPv4 traffic in the tunnel"
+ else
+ SERVER_IP="$SERVER_IP6_TUN"
+ echo "Running IPv6 traffic in the tunnel"
+ fi
+
+ ip netns exec "$CLIENT_NS" netperf -t TCP_STREAM -l 5 -H "$SERVER_IP" -- \
+ -m 80000 > /dev/null
+
+ PACKETS_SERVER=$(ip netns exec "$SERVER_NS" "$IPTABLES-save" -c -t raw | sed -rn '/ --comment bigtcp/{s/^\[([0-9]+):.*/\1/p;q}')
+ PACKETS_CLIENT=$(ip netns exec "$CLIENT_NS" "$IPTABLES-save" -c -t raw | sed -rn '/ --comment bigtcp/{s/^\[([0-9]+):.*/\1/p;q}')
+ PACKETS_SACK=$(ip netns exec "$SERVER_NS" "$IPTABLES_SACK-save" -c -t raw | sed -rn '/ --comment sack/{s/^\[([0-9]+):.*/\1/p;q}')
+ ip netns exec "$SERVER_NS" "$IPTABLES" -w -t raw -D PREROUTING -i "${CAPTURE_IFACE}1" -m length ! --length 0:65535 -m comment --comment "bigtcp"
+ ip netns exec "$CLIENT_NS" "$IPTABLES" -w -t raw -D OUTPUT -o "${CAPTURE_IFACE}0" -m length ! --length 0:65535 -m comment --comment "bigtcp"
+ ip netns exec "$SERVER_NS" "$IPTABLES_SACK" -w -t raw -D OUTPUT -o "tun1" -p tcp -m tcp --tcp-flags ACK ACK --tcp-option 5 -m comment --comment "sack"
+
+ echo "Captured BIG TCP RX packets: $PACKETS_SERVER"
+ echo "Captured BIG TCP TX packets: $PACKETS_CLIENT"
+ echo "Captured TCP SACK packets: $PACKETS_SACK"
+ [ "$PACKETS_SERVER" -gt "$PACKETS_THRESHOLD" ] || return 1
+ [ "$PACKETS_CLIENT" -gt "$PACKETS_THRESHOLD" ] || return 1
+ [ "$PACKETS_SACK" -lt "$(( PACKETS_CLIENT / 2 ))" ] || return 1
+}
+
+if ! netperf -V &> /dev/null; then
+ echo "SKIP: Could not run test without netperf tool"
+ exit "$ksft_skip"
+fi
+
+if ! iptables --version &> /dev/null; then
+ echo "SKIP: Could not run test without iptables tool"
+ exit "$ksft_skip"
+fi
+
+if ! ethtool --version &> /dev/null; then
+ echo "SKIP: Could not run test without ethtool tool"
+ exit "$ksft_skip"
+fi
+
+if ! ip link help 2>&1 | grep gso_ipv4_max_size &> /dev/null; then
+ echo "SKIP: Could not run test without gso/gro_ipv4_max_size supported in ip-link"
+ exit "$ksft_skip"
+fi
+
+WORKDIR=$(mktemp -d)
+trap cleanup EXIT
+setup
+for tunnel in vxlan geneve; do
+ for tun_family in 4 6; do
+ for traffic_family in 4 6; do
+ for csum_offload in on off; do
+ setup_tunnel "$tunnel" "$tun_family" "$csum_offload" || exit "$?"
+ do_test "$tun_family" "$traffic_family" "$csum_offload" || exit "$?"
+ cleanup_tunnel
+ done
+ done
+ done
+done
--
2.54.0
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 0/9] BIG TCP for UDP tunnels
@ 2026-07-15 6:11 ` zebang.li
0 siblings, 0 replies; 23+ messages in thread
From: Nikolay Aleksandrov @ 2026-07-11 9:47 UTC (permalink / raw)
To: Alice Mikityanska, Daniel Borkmann, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Xin Long, Willem de Bruijn,
Willem de Bruijn, David Ahern
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
On 10/07/2026 16:42, Alice Mikityanska wrote:
> From: Alice Mikityanska <alice@isovalent.com>
>
> This series is a follow-up to "BIG TCP without HBH in IPv6", and it adds
> support for BIG TCP IPv4/IPv6 workloads in vxlan and geneve. Now that
> IPv6 BIG TCP doesn't require stripping the HBH in all various
> combinations in tunneled traffic, adding BIG TCP becomes feasible.
>
> Patch 01 adds accessors for the length field in the UDP header, as
> suggested by Paolo in review. The usage of udp_set_len is then added in
> the following patches that start using length=0 in BIG TCP UDP packets.
>
> Patches 02-04 close the gaps that prevent BIG TCP packets from going
> through UDP tunnel code.
>
> Patch 05 validates packets in udp_gro_receive to exclude packets with
> length=0 from GRO aggregation.
>
> Patch 06 is for proper formatting in tcpdump (set UDP len to 0 rather
> than a trimmed value on overflow).
>
> Patches 07-08 bump up tso_max_size for VXLAN and GENEVE.
>
> Patch 09 adds selftests.
>
> Thanks all!
>
> v9 changes: Converted the selftest to iptables counters to avoid the
> issue with tcpdump pcaps taking all space in /tmp.
>
> v8: https://lore.kernel.org/netdev/20260706181941.385672-1-alice.kernel@fastmail.im/
>
> v8 changes: Addressed Paolo's and Jason's review comments. Made the
> selftest more robust, added checks for SACK and mode with disabled tx
> checksum offload on lower veth netdevs. Added details to commit
> messages. Kept skb_segment logic unchanged, because the frags overflow
> issue is not specific to BIG TCP.
>
> v7: https://lore.kernel.org/netdev/20260611192955.604661-1-alice.kernel@fastmail.im/
>
> v7 changes: Addressed Paolo's comments to properly block malformed
> packets with UDP length=0 at udp_rcv level.
>
> v6: https://lore.kernel.org/netdev/20260602093931.516281-1-alice.kernel@fastmail.im/
>
> v6 changes: Lowered the packets threshold in the selftest to pass
> upstream CI on debug kernels, also made it configurable.
>
> v5: https://lore.kernel.org/netdev/20260526161200.1135899-1-alice.kernel@fastmail.im/
>
> v5 changes: Rebased, dropped one of the patches that came in via the net
> tree, addressed an overflow in nsim_do_psp found by Sashiko.
>
> v4: https://lore.kernel.org/netdev/20260512165648.386518-1-alice.kernel@fastmail.im/
>
> v4 changes: Rebased, addressed Sashiko AI review [1] and Willem's
> comment about netperf flags.
>
> My comments on Sashiko AI review per patch:
>
> 01: I'd prefer to keep the cases that I haven't tested outside of the
> scope of this series, which is for VXLAN/GENEVE tunnels, not for ESP.
>
> 02: The patch doesn't have behavioral changes other than fixing the
> checksum. The final uh->len assignment assigns the actual length, not
> 64k.
>
> 03: The check can't be loosened, because total_len is also assigned to
> UDP length. BIG TCP works in the mode without GRO hint option.
>
> 04: Fixed the fallback value for udplen. BIG TCP is fine, it's the
> uh->len = 0 case, uh->len can't exceed 64k.
>
> 05: In the BIG TCP case, partial GSO splits the SKB in two. If full
> segmentation is needed, the SKB is split in many MSS-sized SKBs without
> fragments.
>
> 06: Invalid packets from the wire are addressed in 08.
>
> 07: __udp_gso_segment only handles UDP GSO packets, which can't be
> bigger than 64k. Kept udp_set_len_short in nf_nat_mangle_udp_packet, as
> the function doesn't support BIG TCP packets anyway (see
> mangle_contents).
>
> 08: udp_gro_receive handles packets before aggregation, there are no BIG
> TCP packets at this point. RFC 768 doesn't say that padded UDP packets
> are valid. Real jumbograms don't seem to be supported in this path
> anyway.
>
> 09: The packet goes to skb_udp_tunnel_segment, not __udp_gso_segment.
> __skb_udp_tunnel_segment handles this case.
>
> 12: Improved process cleanup by killing everything inside netns before
> deleting them, and by avoiding killing netserver outside of netns.
> netperf with -r in TCP_STREAM mode works, and the option has the
> intended effect, but I replaced it with -m. Added dependency check for
> tcpdump.
>
> [1]: https://sashiko.dev/#/patchset/20260410150943.993350-1-alice.kernel%40fastmail.im
>
> v3: https://lore.kernel.org/netdev/20260410150943.993350-1-alice.kernel@fastmail.im/
>
> v3 changes: Fixed the redirect in the selftest, rebased over my L2TP fix
> [2] for the syzbot report [3].
>
> [2]: https://lore.kernel.org/netdev/20260403174949.843941-1-alice.kernel@fastmail.im/
> [3]: https://lore.kernel.org/netdev/69a1dfba.050a0220.3a55be.0026.GAE@google.com/
>
> v2: https://lore.kernel.org/netdev/20260226201600.222044-1-alice.kernel@fastmail.im/
>
> v2 changes: Addressed the review comments: added UDP len helpers,
> consolidated UDP len sanity checks in patch 08 into one, added
> selftests. Added fixups to related code (patch 01-03).
>
> v1: https://lore.kernel.org/netdev/20250923134742.1399800-1-maxtram95@gmail.com/
>
> Alice Mikityanska (8):
> net: Use helpers to get/set UDP len tree-wide
> net: Enable BIG TCP with partial GSO
> udp: Support BIG TCP GSO packets where they can occur
> udp: Support gro_ipv4_max_size > 65536
> udp: Validate UDP length in udp_gro_receive
> udp: Set length in UDP header to 0 for big GSO packets
> vxlan: Enable BIG TCP packets
> selftests: net: Add a test for BIG TCP in UDP tunnels
>
> Daniel Borkmann (1):
> geneve: Enable BIG TCP packets
>
> drivers/infiniband/core/lag.c | 2 +-
> drivers/infiniband/sw/rxe/rxe_net.c | 4 +-
> drivers/net/amt.c | 6 +-
> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +-
> drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +-
> drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
> drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
> .../marvell/octeontx2/nic/otx2_txrx.c | 2 +-
> .../net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-
> .../ethernet/mellanox/mlx5/core/en_selftest.c | 2 +-
> drivers/net/ethernet/sfc/falcon/selftest.c | 4 +-
> drivers/net/ethernet/sfc/selftest.c | 4 +-
> drivers/net/ethernet/sfc/siena/selftest.c | 4 +-
> drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +-
> .../stmicro/stmmac/stmmac_selftests.c | 4 +-
> drivers/net/geneve.c | 4 +-
> drivers/net/netconsole.c | 2 +-
> drivers/net/netdevsim/dev.c | 2 +-
> drivers/net/netdevsim/psample.c | 2 +-
> drivers/net/netdevsim/psp.c | 8 +-
> drivers/net/vxlan/vxlan_core.c | 2 +
> drivers/net/wireguard/receive.c | 2 +-
> include/linux/udp.h | 27 +++
> include/trace/events/icmp.h | 2 +-
> lib/tests/blackhole_dev_kunit.c | 2 +-
> net/6lowpan/nhc_udp.c | 10 +-
> net/core/pktgen.c | 4 +-
> net/core/selftests.c | 4 +-
> net/core/skbuff.c | 10 +-
> net/core/tso.c | 3 +-
> net/ipv4/esp4.c | 2 +-
> net/ipv4/fou_core.c | 2 +-
> net/ipv4/ipconfig.c | 6 +-
> net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 4 +-
> net/ipv4/route.c | 2 +-
> net/ipv4/udp.c | 7 +-
> net/ipv4/udp_offload.c | 49 ++---
> net/ipv4/udp_tunnel_core.c | 2 +-
> net/ipv6/esp6.c | 5 +-
> net/ipv6/fou6.c | 2 +-
> net/ipv6/ip6_udp_tunnel.c | 2 +-
> net/ipv6/udp.c | 7 +-
> net/ipv6/udp_offload.c | 2 +-
> net/l2tp/l2tp_core.c | 2 +-
> net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
> net/netfilter/nf_conntrack_proto_udp.c | 15 +-
> net/netfilter/nf_log_syslog.c | 2 +-
> net/netfilter/nf_nat_helper.c | 2 +-
> net/psp/psp_main.c | 2 +-
> net/sched/act_csum.c | 4 +-
> net/xfrm/xfrm_nat_keepalive.c | 2 +-
> tools/testing/selftests/net/Makefile | 1 +
> .../testing/selftests/net/big_tcp_tunnels.sh | 188 ++++++++++++++++++
> 53 files changed, 340 insertions(+), 102 deletions(-)
> create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
>
Very nice work. The set LGTM.
For the series:
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Thanks,
Nik
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 0/9] BIG TCP for UDP tunnels
@ 2026-07-15 6:11 ` zebang.li
0 siblings, 0 replies; 23+ messages in thread
From: zebang.li @ 2026-07-15 6:11 UTC (permalink / raw)
To: alice.kernel
Cc: alice, andrew+netdev, daniel, davem, dsahern, edumazet, fw, horms,
kuba, lucien.xin, netdev, pabeni, razor, shuah, stfomichev,
willemb, willemdebruijn.kernel, nh78.kim, kwangho2.kim, h10.kim,
hongfei.tang, yajie.yan
On 10/07/2026 16:42, Alice Mikityanska wrote:
> From: Alice Mikityanska <alice@isovalent.com>
>
> This series is a follow-up to "BIG TCP without HBH in IPv6", and it adds
> support for BIG TCP IPv4/IPv6 workloads in vxlan and geneve. Now that
> IPv6 BIG TCP doesn't require stripping the HBH in all various
> combinations in tunneled traffic, adding BIG TCP becomes feasible.
>
> Patch 01 adds accessors for the length field in the UDP header, as
> suggested by Paolo in review. The usage of udp_set_len is then added in
> the following patches that start using length=0 in BIG TCP UDP packets.
>
> Patches 02-04 close the gaps that prevent BIG TCP packets from going
> through UDP tunnel code.
>
> Patch 05 validates packets in udp_gro_receive to exclude packets with
> length=0 from GRO aggregation.
>
> Patch 06 is for proper formatting in tcpdump (set UDP len to 0 rather
> than a trimmed value on overflow).
>
> Patches 07-08 bump up tso_max_size for VXLAN and GENEVE.
>
> Patch 09 adds selftests.
>
> Thanks all!
>
> v9 changes: Converted the selftest to iptables counters to avoid the
> issue with tcpdump pcaps taking all space in /tmp.
>
> v8: https://lore.kernel.org/netdev/20260706181941.385672-1-alice.kernel@fastmail.im/
>
> v8 changes: Addressed Paolo's and Jason's review comments. Made the
> selftest more robust, added checks for SACK and mode with disabled tx
> checksum offload on lower veth netdevs. Added details to commit
> messages. Kept skb_segment logic unchanged, because the frags overflow
> issue is not specific to BIG TCP.
>
> v7: https://lore.kernel.org/netdev/20260611192955.604661-1-alice.kernel@fastmail.im/
>
> v7 changes: Addressed Paolo's comments to properly block malformed
> packets with UDP length=0 at udp_rcv level.
>
> v6: https://lore.kernel.org/netdev/20260602093931.516281-1-alice.kernel@fastmail.im/
>
> v6 changes: Lowered the packets threshold in the selftest to pass
> upstream CI on debug kernels, also made it configurable.
>
> v5: https://lore.kernel.org/netdev/20260526161200.1135899-1-alice.kernel@fastmail.im/
>
> v5 changes: Rebased, dropped one of the patches that came in via the net
> tree, addressed an overflow in nsim_do_psp found by Sashiko.
>
> v4: https://lore.kernel.org/netdev/20260512165648.386518-1-alice.kernel@fastmail.im/
>
> v4 changes: Rebased, addressed Sashiko AI review [1] and Willem's
> comment about netperf flags.
>
> My comments on Sashiko AI review per patch:
>
> 01: I'd prefer to keep the cases that I haven't tested outside of the
> scope of this series, which is for VXLAN/GENEVE tunnels, not for ESP.
>
> 02: The patch doesn't have behavioral changes other than fixing the
> checksum. The final uh->len assignment assigns the actual length, not
> 64k.
>
> 03: The check can't be loosened, because total_len is also assigned to
> UDP length. BIG TCP works in the mode without GRO hint option.
>
> 04: Fixed the fallback value for udplen. BIG TCP is fine, it's the
> uh->len = 0 case, uh->len can't exceed 64k.
>
> 05: In the BIG TCP case, partial GSO splits the SKB in two. If full
> segmentation is needed, the SKB is split in many MSS-sized SKBs without
> fragments.
>
> 06: Invalid packets from the wire are addressed in 08.
>
> 07: __udp_gso_segment only handles UDP GSO packets, which can't be
> bigger than 64k. Kept udp_set_len_short in nf_nat_mangle_udp_packet, as
> the function doesn't support BIG TCP packets anyway (see
> mangle_contents).
>
> 08: udp_gro_receive handles packets before aggregation, there are no BIG
> TCP packets at this point. RFC 768 doesn't say that padded UDP packets
> are valid. Real jumbograms don't seem to be supported in this path
> anyway.
>
> 09: The packet goes to skb_udp_tunnel_segment, not __udp_gso_segment.
> __skb_udp_tunnel_segment handles this case.
>
> 12: Improved process cleanup by killing everything inside netns before
> deleting them, and by avoiding killing netserver outside of netns.
> netperf with -r in TCP_STREAM mode works, and the option has the
> intended effect, but I replaced it with -m. Added dependency check for
> tcpdump.
>
> [1]: https://sashiko.dev/#/patchset/20260410150943.993350-1-alice.kernel%40fastmail.im
>
> v3: https://lore.kernel.org/netdev/20260410150943.993350-1-alice.kernel@fastmail.im/
>
> v3 changes: Fixed the redirect in the selftest, rebased over my L2TP fix
> [2] for the syzbot report [3].
>
> [2]: https://lore.kernel.org/netdev/20260403174949.843941-1-alice.kernel@fastmail.im/
> [3]: https://lore.kernel.org/netdev/69a1dfba.050a0220.3a55be.0026.GAE@google.com/
>
> v2: https://lore.kernel.org/netdev/20260226201600.222044-1-alice.kernel@fastmail.im/
>
> v2 changes: Addressed the review comments: added UDP len helpers,
> consolidated UDP len sanity checks in patch 08 into one, added
> selftests. Added fixups to related code (patch 01-03).
>
> v1: https://lore.kernel.org/netdev/20250923134742.1399800-1-maxtram95@gmail.com/
>
> Alice Mikityanska (8):
> net: Use helpers to get/set UDP len tree-wide
> net: Enable BIG TCP with partial GSO
> udp: Support BIG TCP GSO packets where they can occur
> udp: Support gro_ipv4_max_size > 65536
> udp: Validate UDP length in udp_gro_receive
> udp: Set length in UDP header to 0 for big GSO packets
> vxlan: Enable BIG TCP packets
> selftests: net: Add a test for BIG TCP in UDP tunnels
>
> Daniel Borkmann (1):
> geneve: Enable BIG TCP packets
>
> drivers/infiniband/core/lag.c | 2 +-
> drivers/infiniband/sw/rxe/rxe_net.c | 4 +-
> drivers/net/amt.c | 6 +-
> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +-
> drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +-
> drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
> drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
> .../marvell/octeontx2/nic/otx2_txrx.c | 2 +-
> .../net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-
> .../ethernet/mellanox/mlx5/core/en_selftest.c | 2 +-
> drivers/net/ethernet/sfc/falcon/selftest.c | 4 +-
> drivers/net/ethernet/sfc/selftest.c | 4 +-
> drivers/net/ethernet/sfc/siena/selftest.c | 4 +-
> drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +-
> .../stmicro/stmmac/stmmac_selftests.c | 4 +-
> drivers/net/geneve.c | 4 +-
> drivers/net/netconsole.c | 2 +-
> drivers/net/netdevsim/dev.c | 2 +-
> drivers/net/netdevsim/psample.c | 2 +-
> drivers/net/netdevsim/psp.c | 8 +-
> drivers/net/vxlan/vxlan_core.c | 2 +
> drivers/net/wireguard/receive.c | 2 +-
> include/linux/udp.h | 27 +++
> include/trace/events/icmp.h | 2 +-
> lib/tests/blackhole_dev_kunit.c | 2 +-
> net/6lowpan/nhc_udp.c | 10 +-
> net/core/pktgen.c | 4 +-
> net/core/selftests.c | 4 +-
> net/core/skbuff.c | 10 +-
> net/core/tso.c | 3 +-
> net/ipv4/esp4.c | 2 +-
> net/ipv4/fou_core.c | 2 +-
> net/ipv4/ipconfig.c | 6 +-
> net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 4 +-
> net/ipv4/route.c | 2 +-
> net/ipv4/udp.c | 7 +-
> net/ipv4/udp_offload.c | 49 ++---
> net/ipv4/udp_tunnel_core.c | 2 +-
> net/ipv6/esp6.c | 5 +-
> net/ipv6/fou6.c | 2 +-
> net/ipv6/ip6_udp_tunnel.c | 2 +-
> net/ipv6/udp.c | 7 +-
> net/ipv6/udp_offload.c | 2 +-
> net/l2tp/l2tp_core.c | 2 +-
> net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
> net/netfilter/nf_conntrack_proto_udp.c | 15 +-
> net/netfilter/nf_log_syslog.c | 2 +-
> net/netfilter/nf_nat_helper.c | 2 +-
> net/psp/psp_main.c | 2 +-
> net/sched/act_csum.c | 4 +-
> net/xfrm/xfrm_nat_keepalive.c | 2 +-
> tools/testing/selftests/net/Makefile | 1 +
> .../testing/selftests/net/big_tcp_tunnels.sh | 188 ++++++++++++++++++
> 53 files changed, 340 insertions(+), 102 deletions(-)
> create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
>
Hi Alice,
This patch looks promising, but I noticed that it does not include a modification for `skb_gro_receive`.
Currently, for UDP data aggregated via GRO, if the resulting packet size exceeds 65536 (`GRO_LEGACY_MAX_SIZE`), this check will return `-E2BIG`.
To allow UDP GRO aggregation beyond this limit (similar to the existing TCP behavior), we should update the condition to include `IPPROTO_UDP`.
I suggest the following modification:
diff --git a/net/core/gro.c b/net/core/gro.c
index 35f2f708f010..01e56ad629c2 100644
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -117,7 +117,7 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
return -E2BIG;
if (unlikely(p->len + len >= GRO_LEGACY_MAX_SIZE)) {
- if (NAPI_GRO_CB(skb)->proto != IPPROTO_TCP ||
+ if ((NAPI_GRO_CB(skb)->proto != IPPROTO_TCP && NAPI_GRO_CB(skb)->proto != IPPROTO_UDP) ||
p->encapsulation)
return -E2BIG;
}
Thanks,
zebang
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 0/9] BIG TCP for UDP tunnels
[not found] ` <(raw)>
@ 2026-07-15 9:06 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-15 9:06 UTC (permalink / raw)
To: zebang.li
Cc: Alice Mikityanska, Andrew Lunn, Daniel Borkmann, David S. Miller,
David Ahern, Eric Dumazet, Florian Westphal, Simon Horman,
Jakub Kicinski, Xin Long, netdev, Paolo Abeni,
Nikolay Aleksandrov, Shuah Khan, Stanislav Fomichev,
Willem de Bruijn, Willem de Bruijn, nh78.kim, kwangho2.kim,
h10.kim, hongfei.tang, yajie.yan
On Wed, Jul 15, 2026, at 09:11, zebang.li wrote:
> On 10/07/2026 16:42, Alice Mikityanska wrote:
>> From: Alice Mikityanska <alice@isovalent.com>
>>
>> This series is a follow-up to "BIG TCP without HBH in IPv6", and it adds
>> support for BIG TCP IPv4/IPv6 workloads in vxlan and geneve. Now that
>> IPv6 BIG TCP doesn't require stripping the HBH in all various
>> combinations in tunneled traffic, adding BIG TCP becomes feasible.
>>
>> Patch 01 adds accessors for the length field in the UDP header, as
>> suggested by Paolo in review. The usage of udp_set_len is then added in
>> the following patches that start using length=0 in BIG TCP UDP packets.
>>
>> Patches 02-04 close the gaps that prevent BIG TCP packets from going
>> through UDP tunnel code.
>>
>> Patch 05 validates packets in udp_gro_receive to exclude packets with
>> length=0 from GRO aggregation.
>>
>> Patch 06 is for proper formatting in tcpdump (set UDP len to 0 rather
>> than a trimmed value on overflow).
>>
>> Patches 07-08 bump up tso_max_size for VXLAN and GENEVE.
>>
>> Patch 09 adds selftests.
>>
>> Thanks all!
>>
>> v9 changes: Converted the selftest to iptables counters to avoid the
>> issue with tcpdump pcaps taking all space in /tmp.
>>
>> v8: https://lore.kernel.org/netdev/20260706181941.385672-1-alice.kernel@fastmail.im/
>>
>> v8 changes: Addressed Paolo's and Jason's review comments. Made the
>> selftest more robust, added checks for SACK and mode with disabled tx
>> checksum offload on lower veth netdevs. Added details to commit
>> messages. Kept skb_segment logic unchanged, because the frags overflow
>> issue is not specific to BIG TCP.
>>
>> v7: https://lore.kernel.org/netdev/20260611192955.604661-1-alice.kernel@fastmail.im/
>>
>> v7 changes: Addressed Paolo's comments to properly block malformed
>> packets with UDP length=0 at udp_rcv level.
>>
>> v6: https://lore.kernel.org/netdev/20260602093931.516281-1-alice.kernel@fastmail.im/
>>
>> v6 changes: Lowered the packets threshold in the selftest to pass
>> upstream CI on debug kernels, also made it configurable.
>>
>> v5: https://lore.kernel.org/netdev/20260526161200.1135899-1-alice.kernel@fastmail.im/
>>
>> v5 changes: Rebased, dropped one of the patches that came in via the net
>> tree, addressed an overflow in nsim_do_psp found by Sashiko.
>>
>> v4: https://lore.kernel.org/netdev/20260512165648.386518-1-alice.kernel@fastmail.im/
>>
>> v4 changes: Rebased, addressed Sashiko AI review [1] and Willem's
>> comment about netperf flags.
>>
>> My comments on Sashiko AI review per patch:
>>
>> 01: I'd prefer to keep the cases that I haven't tested outside of the
>> scope of this series, which is for VXLAN/GENEVE tunnels, not for ESP.
>>
>> 02: The patch doesn't have behavioral changes other than fixing the
>> checksum. The final uh->len assignment assigns the actual length, not
>> 64k.
>>
>> 03: The check can't be loosened, because total_len is also assigned to
>> UDP length. BIG TCP works in the mode without GRO hint option.
>>
>> 04: Fixed the fallback value for udplen. BIG TCP is fine, it's the
>> uh->len = 0 case, uh->len can't exceed 64k.
>>
>> 05: In the BIG TCP case, partial GSO splits the SKB in two. If full
>> segmentation is needed, the SKB is split in many MSS-sized SKBs without
>> fragments.
>>
>> 06: Invalid packets from the wire are addressed in 08.
>>
>> 07: __udp_gso_segment only handles UDP GSO packets, which can't be
>> bigger than 64k. Kept udp_set_len_short in nf_nat_mangle_udp_packet, as
>> the function doesn't support BIG TCP packets anyway (see
>> mangle_contents).
>>
>> 08: udp_gro_receive handles packets before aggregation, there are no BIG
>> TCP packets at this point. RFC 768 doesn't say that padded UDP packets
>> are valid. Real jumbograms don't seem to be supported in this path
>> anyway.
>>
>> 09: The packet goes to skb_udp_tunnel_segment, not __udp_gso_segment.
>> __skb_udp_tunnel_segment handles this case.
>>
>> 12: Improved process cleanup by killing everything inside netns before
>> deleting them, and by avoiding killing netserver outside of netns.
>> netperf with -r in TCP_STREAM mode works, and the option has the
>> intended effect, but I replaced it with -m. Added dependency check for
>> tcpdump.
>>
>> [1]: https://sashiko.dev/#/patchset/20260410150943.993350-1-alice.kernel%40fastmail.im
>>
>> v3: https://lore.kernel.org/netdev/20260410150943.993350-1-alice.kernel@fastmail.im/
>>
>> v3 changes: Fixed the redirect in the selftest, rebased over my L2TP fix
>> [2] for the syzbot report [3].
>>
>> [2]: https://lore.kernel.org/netdev/20260403174949.843941-1-alice.kernel@fastmail.im/
>> [3]: https://lore.kernel.org/netdev/69a1dfba.050a0220.3a55be.0026.GAE@google.com/
>>
>> v2: https://lore.kernel.org/netdev/20260226201600.222044-1-alice.kernel@fastmail.im/
>>
>> v2 changes: Addressed the review comments: added UDP len helpers,
>> consolidated UDP len sanity checks in patch 08 into one, added
>> selftests. Added fixups to related code (patch 01-03).
>>
>> v1: https://lore.kernel.org/netdev/20250923134742.1399800-1-maxtram95@gmail.com/
>>
>> Alice Mikityanska (8):
>> net: Use helpers to get/set UDP len tree-wide
>> net: Enable BIG TCP with partial GSO
>> udp: Support BIG TCP GSO packets where they can occur
>> udp: Support gro_ipv4_max_size > 65536
>> udp: Validate UDP length in udp_gro_receive
>> udp: Set length in UDP header to 0 for big GSO packets
>> vxlan: Enable BIG TCP packets
>> selftests: net: Add a test for BIG TCP in UDP tunnels
>>
>> Daniel Borkmann (1):
>> geneve: Enable BIG TCP packets
>>
>> drivers/infiniband/core/lag.c | 2 +-
>> drivers/infiniband/sw/rxe/rxe_net.c | 4 +-
>> drivers/net/amt.c | 6 +-
>> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +-
>> drivers/net/ethernet/intel/iavf/iavf_txrx.c | 2 +-
>> drivers/net/ethernet/intel/ice/ice_txrx.c | 2 +-
>> drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
>> .../marvell/octeontx2/nic/otx2_txrx.c | 2 +-
>> .../net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-
>> .../ethernet/mellanox/mlx5/core/en_selftest.c | 2 +-
>> drivers/net/ethernet/sfc/falcon/selftest.c | 4 +-
>> drivers/net/ethernet/sfc/selftest.c | 4 +-
>> drivers/net/ethernet/sfc/siena/selftest.c | 4 +-
>> drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +-
>> .../stmicro/stmmac/stmmac_selftests.c | 4 +-
>> drivers/net/geneve.c | 4 +-
>> drivers/net/netconsole.c | 2 +-
>> drivers/net/netdevsim/dev.c | 2 +-
>> drivers/net/netdevsim/psample.c | 2 +-
>> drivers/net/netdevsim/psp.c | 8 +-
>> drivers/net/vxlan/vxlan_core.c | 2 +
>> drivers/net/wireguard/receive.c | 2 +-
>> include/linux/udp.h | 27 +++
>> include/trace/events/icmp.h | 2 +-
>> lib/tests/blackhole_dev_kunit.c | 2 +-
>> net/6lowpan/nhc_udp.c | 10 +-
>> net/core/pktgen.c | 4 +-
>> net/core/selftests.c | 4 +-
>> net/core/skbuff.c | 10 +-
>> net/core/tso.c | 3 +-
>> net/ipv4/esp4.c | 2 +-
>> net/ipv4/fou_core.c | 2 +-
>> net/ipv4/ipconfig.c | 6 +-
>> net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 4 +-
>> net/ipv4/route.c | 2 +-
>> net/ipv4/udp.c | 7 +-
>> net/ipv4/udp_offload.c | 49 ++---
>> net/ipv4/udp_tunnel_core.c | 2 +-
>> net/ipv6/esp6.c | 5 +-
>> net/ipv6/fou6.c | 2 +-
>> net/ipv6/ip6_udp_tunnel.c | 2 +-
>> net/ipv6/udp.c | 7 +-
>> net/ipv6/udp_offload.c | 2 +-
>> net/l2tp/l2tp_core.c | 2 +-
>> net/netfilter/ipvs/ip_vs_xmit.c | 2 +-
>> net/netfilter/nf_conntrack_proto_udp.c | 15 +-
>> net/netfilter/nf_log_syslog.c | 2 +-
>> net/netfilter/nf_nat_helper.c | 2 +-
>> net/psp/psp_main.c | 2 +-
>> net/sched/act_csum.c | 4 +-
>> net/xfrm/xfrm_nat_keepalive.c | 2 +-
>> tools/testing/selftests/net/Makefile | 1 +
>> .../testing/selftests/net/big_tcp_tunnels.sh | 188 ++++++++++++++++++
>> 53 files changed, 340 insertions(+), 102 deletions(-)
>> create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
>>
>
>
> Hi Alice,
>
> This patch looks promising, but I noticed that it does not include a
> modification for `skb_gro_receive`.
>
> Currently, for UDP data aggregated via GRO, if the resulting packet
> size exceeds 65536 (`GRO_LEGACY_MAX_SIZE`), this check will return
> `-E2BIG`.
>
> To allow UDP GRO aggregation beyond this limit (similar to the existing
> TCP behavior), we should update the condition to include `IPPROTO_UDP`.
Thanks for the feedback! That's a good idea for future development,
however, I'd like to keep the scope of this effort limited to BIG TCP.
The series is already big enough, and adding UDP GRO might be not as
trivial as it seems. At the very least, it requires adding another
selftest to cover the new paths. In the worst case, it might need more
tweaks in the datapath in case something breaks at later points in the
pipeline. Moreover, since UDP GRO is not transparent for the userspace
(unlike BIG TCP), the userspace might rely on assumptions about max
aggregation size, and this topic needs additional research.
To sum up, it's a good direction for further research, which can be done
independently after merging this series, but I'd rather keep the scope
of this series clear and limited to BIG TCP. Note that the current
version of skb_gro_receive doesn't block tunneled BIG TCP traffic, which
is proved by the selftest and manual testing.
Thanks,
Alice
> I suggest the following modification:
>
> diff --git a/net/core/gro.c b/net/core/gro.c
> index 35f2f708f010..01e56ad629c2 100644
> --- a/net/core/gro.c
> +++ b/net/core/gro.c
> @@ -117,7 +117,7 @@ int skb_gro_receive(struct sk_buff *p, struct
> sk_buff *skb)
> return -E2BIG;
> if (unlikely(p->len + len >= GRO_LEGACY_MAX_SIZE)) {
> - if (NAPI_GRO_CB(skb)->proto != IPPROTO_TCP ||
> + if ((NAPI_GRO_CB(skb)->proto != IPPROTO_TCP &&
> NAPI_GRO_CB(skb)->proto != IPPROTO_UDP) ||
> p->encapsulation)
> return -E2BIG;
> }
>
> Thanks,
> zebang
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide
2026-07-10 13:42 ` [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide Alice Mikityanska
@ 2026-07-16 14:46 ` Simon Horman
2026-07-16 15:18 ` Alice Mikityanska
0 siblings, 1 reply; 23+ messages in thread
From: Simon Horman @ 2026-07-16 14:46 UTC (permalink / raw)
To: alice.kernel
Cc: Simon Horman, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev, alice
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
--- Patch [1]: [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide ---
commit 113d28557bcedccc492f330fafdaaf1377eb2e79
Author: Alice Mikityanska <alice@isovalent.com>
net: Use helpers to get/set UDP len tree-wide
This commit introduces helpers for setting and getting the UDP header length
tree-wide. It prepares the codebase to support BIG TCP for UDP tunnels by
explicitly handling cases where UDP length might be 0 for packets larger
than 65535 bytes.
> diff --git a/net/6lowpan/nhc_udp.c b/net/6lowpan/nhc_udp.c
> index 0a506c77283dd..ed4227e6db744 100644
> --- a/net/6lowpan/nhc_udp.c
> +++ b/net/6lowpan/nhc_udp.c
> @@ -88,16 +88,16 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed)
> switch (lowpan_dev(skb->dev)->lltype) {
> case LOWPAN_LLTYPE_IEEE802154:
> if (lowpan_802154_cb(skb)->d_size)
> - uh.len = htons(lowpan_802154_cb(skb)->d_size -
> - sizeof(struct ipv6hdr));
> + udp_set_len_short(&uh, lowpan_802154_cb(skb)->d_size -
> + sizeof(struct ipv6hdr));
[Severity: High]
If a crafted packet specifies a datagram size smaller than
sizeof(struct ipv6hdr), won't this subtraction underflow?
The resulting massive unsigned value passed to udp_set_len_short() would
then trigger the DEBUG_NET_WARN_ON_ONCE, potentially causing a panic if
panic_on_warn is set.
> [ ... ]
> diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> index 29651b1a0bc70..493e2b9e16fbc 100644
> --- a/net/ipv4/udp_offload.c
> +++ b/net/ipv4/udp_offload.c
> [ ... ]
> @@ -915,12 +914,12 @@ static int udp_gro_complete_segment(struct sk_buff *skb)
> int udp_gro_complete(struct sk_buff *skb, int nhoff,
> udp_lookup_t lookup)
> {
> - __be16 newlen = htons(skb->len - nhoff);
> struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
> + unsigned int newlen = skb->len - nhoff;
> struct sock *sk;
> int err;
>
> - uh->len = newlen;
> + udp_set_len_short(uh, newlen);
[Severity: High]
If gro_max_size is configured larger than 65535 (which is supported and used
for BIG TCP), can't UDP GRO aggregate packets such that newlen > 65535?
This would instantly trigger the DEBUG_NET_WARN_ON_ONCE inside
udp_set_len_short() for legitimate large packets.
> [ ... ]
> diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
> index 9ab3728f9630b..0fccb38f074d2 100644
> --- a/net/ipv4/udp_tunnel_core.c
> +++ b/net/ipv4/udp_tunnel_core.c
> @@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
>
> uh->dest = dst_port;
> uh->source = src_port;
> - uh->len = htons(skb->len);
> + udp_set_len_short(uh, skb->len);
[Severity: High]
When transmitting a TCP BIG TCP packet (which can be > 64K) over a UDP
tunnel like VXLAN, skb->len will exceed 65535.
Does using udp_set_len_short() here incorrectly trigger the warning for
valid large GSO payloads?
> [ ... ]
> diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
> index 9adb5775487fa..dcff7fb16ff64 100644
> --- a/net/ipv6/ip6_udp_tunnel.c
> +++ b/net/ipv6/ip6_udp_tunnel.c
> @@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
> uh->dest = dst_port;
> uh->source = src_port;
>
> - uh->len = htons(skb->len);
> + udp_set_len_short(uh, skb->len);
[Severity: High]
This appears to have the same issue as IPv4 tunnels. If a large GSO payload
is sent through an IPv6 UDP tunnel, won't skb->len exceed 65535 and trigger
the warning?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO
2026-07-10 13:42 ` [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO Alice Mikityanska
@ 2026-07-16 14:47 ` Simon Horman
2026-07-16 16:28 ` Alice Mikityanska
0 siblings, 1 reply; 23+ messages in thread
From: Simon Horman @ 2026-07-16 14:47 UTC (permalink / raw)
To: alice.kernel
Cc: Simon Horman, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev, alice
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
--- Patch [2]: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO ---
commit b8199f77774400021642eb53bd60ec1a062a54ef
Author: Alice Mikityanska <alice@isovalent.com>
net: Enable BIG TCP with partial GSO
This commit removes the 65534-byte clamp on segment length in skb_segment
for partial GSO. It stores the gso_by_frags flag early to allow BIG TCP
packets to use larger lengths without accidental resegmentation.
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 18dabb4e9cfa0..6ae4c2b205f2e 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
[ ... ]
> @@ -4852,9 +4853,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
> /* GSO partial only requires that we trim off any excess that
> * doesn't fit into an MSS sized block, so take care of that
> * now.
> - * Cap len to not accidentally hit GSO_BY_FRAGS.
> */
> - partial_segs = min(len, GSO_BY_FRAGS - 1) / mss;
> + partial_segs = len / mss;
[Severity: High]
When removing the clamp on partial GSO segments, mss is scaled up without any
upper bound. For BIG TCP packets, could this construct segments that exceed
MAX_SKB_FRAGS?
If a 512KB packet is passed to skb_segment() for partial GSO, mss is scaled
up to the full packet length. When attempting to build this single large
segment by flattening the frag_list into a new frags array, it appears it
would hit the fragment limit and abort:
net/core/skbuff.c:skb_segment() {
...
if (unlikely(skb_shinfo(nskb)->nr_frags >=
MAX_SKB_FRAGS)) {
net_warn_ratelimited(
"skb_segment: too many frags: %u %u\n",
pos, mss);
err = -EINVAL;
goto err;
}
...
}
Does this deterministically drop BIG TCP traffic over tunnels that require
partial GSO?
[Severity: Medium]
Can the partial_segs calculation exceed 65535 for malicious inputs and cause
a 16-bit truncation?
If a crafted packet with a very small gso_size (for example, mss=1 via an
untrusted packet socket) and a large payload is segmented, len / mss could
produce a value greater than 65535.
When this 32-bit value is later assigned to the 16-bit field in skb_segment():
net/core/skbuff.c:skb_segment() {
...
skb_shinfo(iter)->gso_segs = partial_segs;
...
}
Could this silent truncation corrupt hardware engine programming or Byte Queue
Limits?
> if (partial_segs > 1)
> mss *= partial_segs;
> else
[ ... ]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536
2026-07-10 13:42 ` [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 Alice Mikityanska
@ 2026-07-16 14:47 ` Simon Horman
2026-07-16 17:04 ` Alice Mikityanska
0 siblings, 1 reply; 23+ messages in thread
From: Simon Horman @ 2026-07-16 14:47 UTC (permalink / raw)
To: alice.kernel
Cc: Simon Horman, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev, alice
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
--- Patch [4]: [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 ---
commit 6dfda0f76318408b2e2b33603d561940b926529c
Author: Alice Mikityanska <alice@isovalent.com>
Subject: udp: Support gro_ipv4_max_size > 65536
This commit fixes UDP GRO aggregation for packets larger than 65536 bytes
by setting the UDP length field to 0 during GRO and restoring the true length
from skb->len in udp_rcv().
> diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> index 493e2b9e16fbc..4f9a3922937cc 100644
> --- a/net/ipv4/udp_offload.c
> +++ b/net/ipv4/udp_offload.c
> @@ -919,7 +919,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
> struct sock *sk;
> int err;
>
> - udp_set_len_short(uh, newlen);
> + udp_set_len(uh, newlen);
[Severity: High]
Does setting the UDP length to 0 here (for packets > 65535 bytes) break
software segmentation?
In net/ipv4/udp_offload.c:__udp_gso_segment(), the code adjusts the
pseudo-header checksum by subtracting uh->len:
check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
If uh->len is 0 for BIG TCP packets, this subtraction will fail to remove
the true 32-bit original length from the checksum.
Similarly, in net/ipv4/udp_offload.c:__skb_udp_tunnel_segment(), partial
GSO relies on uh->len to negate the old length:
if (skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL)
partial = (__force __wsum)uh->len;
else
partial = (__force __wsum)htonl(skb->len);
partial = csum_sub(csum_unfold(uh->check), partial);
Will forwarding BIG TCP over UDP packets that fall back to software
segmentation result in corrupted checksums for all generated segments?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive
2026-07-10 13:42 ` [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive Alice Mikityanska
@ 2026-07-16 14:48 ` Simon Horman
2026-07-16 18:32 ` Alice Mikityanska
0 siblings, 1 reply; 23+ messages in thread
From: Simon Horman @ 2026-07-16 14:48 UTC (permalink / raw)
To: alice.kernel
Cc: Simon Horman, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev, alice
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
--- Patch [5]: [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive ---
commit f1316d873c7549e0a49dc98d7614be1dc5b0f66c
Author: Alice Mikityanska <alice@isovalent.com>
udp: Validate UDP length in udp_gro_receive
This patch adds an early check for malformed or padded UDP packets with
len=0 at udp_gro_receive to exclude them from GRO, moving the check out of
udp_gro_receive_segment.
> diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> index 4f9a3922937cc..8f77c8788f6db 100644
> --- a/net/ipv4/udp_offload.c
> +++ b/net/ipv4/udp_offload.c
[ ... ]
> @@ -782,8 +778,14 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
> struct sk_buff *p;
> struct udphdr *uh2;
> unsigned int off = skb_gro_offset(skb);
> + unsigned int ulen;
> int flush = 1;
>
> + /* Do not deal with padded or malicious packets, sorry! */
> + ulen = udp_get_len_short(uh);
> + if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb))
> + goto out;
> +
[Severity: High]
Could this early return bypass inner GRO flow matching for padded UDP tunnel
packets?
When a padded UDP tunnel packet, such as a small TCP ACK inside VXLAN or
GENEVE, arrives in net/ipv4/udp_offload.c:udp_gro_receive() while previous
packets of the same inner flow are held in the GRO list, the
ulen != skb_gro_len(skb) check evaluates to true and triggers the goto out.
Because the goto out path yields pp = NULL and flush = 1, dev_gro_receive()
passes the new padded packet to the network stack immediately, leaving older
packets stuck in the GRO list.
Before this change, the packet would reach inner GRO handlers (like
tcp4_gro_receive()) which would detect the sequence or padding mismatch,
set flush = 1, and return the held packet via pp = p. This ensured older
packets were flushed to the stack before the new padded packet, preserving
delivery order.
Will bypassing this inner flow matching lead to out-of-order delivery for
the inner protocol, resulting in duplicate ACKs and throughput degradation?
> /* We can do L4 aggregation only if the packet can't land in a tunnel
> * otherwise we could corrupt the inner stream. Detecting such packets
> * cannot be foolproof and the aggregation might still happen in some
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 8/9] geneve: Enable BIG TCP packets
2026-07-10 13:42 ` [PATCH net-next v9 8/9] geneve: " Alice Mikityanska
@ 2026-07-16 14:48 ` Simon Horman
2026-07-16 18:45 ` Alice Mikityanska
0 siblings, 1 reply; 23+ messages in thread
From: Simon Horman @ 2026-07-16 14:48 UTC (permalink / raw)
To: alice.kernel
Cc: Simon Horman, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev, alice
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
--- Patch [8]: [PATCH net-next v9 8/9] geneve: Enable BIG TCP packets ---
commit d560b2b7c8bd97bea9e23790fdfc21cfe031b961
Author: Alice Mikityanska <alice@isovalent.com>
geneve: Enable BIG TCP packets
In Cilium we do support BIG TCP, but so far the latter has only been
enabled for direct routing use-cases. A lot of users rely on Cilium
with vxlan/geneve tunneling though. The underlying kernel infra for
tunneling has not been supporting BIG TCP up to this point.
> diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> index 011bf9d833caf..a1639ad53077e 100644
> --- a/drivers/net/geneve.c
> +++ b/drivers/net/geneve.c
> @@ -1745,6 +1745,8 @@ static void geneve_setup(struct net_device *dev)
> dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
>
> netif_keep_dst(dev);
> + netif_set_tso_max_size(dev, GSO_MAX_SIZE);
> +
[Severity: High]
This is a pre-existing issue, but by enabling BIG TCP on Geneve, will it
expose a bug where valid BIG TCP packets are incorrectly dropped?
In geneve_post_decap_hint(), there is a legacy size check that rejects
packets aggregated by GRO to sizes >= 65536 bytes:
drivers/net/geneve.c:geneve_post_decap_hint() {
...
total_len = skb->len - gro_hint->nested_nh_offset;
if (total_len >= GRO_LEGACY_MAX_SIZE)
return -E2BIG;
...
}
When BIG TCP is enabled and the Geneve tunnel is configured with gro_hint,
large flows are aggregated by GRO into packets exceeding 64KB. This will hit
the legacy check and return -E2BIG, causing packet loss for large flows.
> dev->priv_flags &= ~IFF_TX_SKB_SHARING;
> dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
> dev->lltx = true;
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide
2026-07-16 14:46 ` Simon Horman
@ 2026-07-16 15:18 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-16 15:18 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
On Thu, 16 Jul 2026 at 17:47, Simon Horman <horms@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [1]: [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide ---
> commit 113d28557bcedccc492f330fafdaaf1377eb2e79
> Author: Alice Mikityanska <alice@isovalent.com>
>
> net: Use helpers to get/set UDP len tree-wide
>
> This commit introduces helpers for setting and getting the UDP header length
> tree-wide. It prepares the codebase to support BIG TCP for UDP tunnels by
> explicitly handling cases where UDP length might be 0 for packets larger
> than 65535 bytes.
>
> > diff --git a/net/6lowpan/nhc_udp.c b/net/6lowpan/nhc_udp.c
> > index 0a506c77283dd..ed4227e6db744 100644
> > --- a/net/6lowpan/nhc_udp.c
> > +++ b/net/6lowpan/nhc_udp.c
> > @@ -88,16 +88,16 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed)
> > switch (lowpan_dev(skb->dev)->lltype) {
> > case LOWPAN_LLTYPE_IEEE802154:
> > if (lowpan_802154_cb(skb)->d_size)
> > - uh.len = htons(lowpan_802154_cb(skb)->d_size -
> > - sizeof(struct ipv6hdr));
> > + udp_set_len_short(&uh, lowpan_802154_cb(skb)->d_size -
> > + sizeof(struct ipv6hdr));
>
> [Severity: High]
> If a crafted packet specifies a datagram size smaller than
> sizeof(struct ipv6hdr), won't this subtraction underflow?
First, I'd like to emphasize that I'm merely converting direct uh.len
access to the new helper. If there is an existing bug with underflow,
my new helper will expose it with a WARN, which is good. But should
such bugs exist before this refactoring, I don't think that fixing all
of them is in scope of this series.
Addressing the AI concern directly, my AI claims that such underflow
is not possible:
> For fragmented IEEE 802.15.4 packets:
> - d_size is decoded from the FRAG1 header in net/ieee802154/6lowpan/reassembly.c:259.
> - A FRAG1 packet with d_size < sizeof(struct ipv6hdr) is rejected at net/ieee802154/6lowpan/reassembly.c:270.
> - UDP/IPHC decompression is invoked only after that validation, at net/ieee802154/6lowpan/reassembly.c:296.
> - FRAGN packets do not invoke header decompression here; they are queued for reassembly.
> For an unfragmented packet, d_size is explicitly set to zero at net/ieee802154/6lowpan/rx.c:103, selecting the else branch and avoiding the subtraction entirely.
> The resulting massive unsigned value passed to udp_set_len_short() would
> then trigger the DEBUG_NET_WARN_ON_ONCE, potentially causing a panic if
> panic_on_warn is set.
>
> > [ ... ]
> > diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> > index 29651b1a0bc70..493e2b9e16fbc 100644
> > --- a/net/ipv4/udp_offload.c
> > +++ b/net/ipv4/udp_offload.c
> > [ ... ]
> > @@ -915,12 +914,12 @@ static int udp_gro_complete_segment(struct sk_buff *skb)
> > int udp_gro_complete(struct sk_buff *skb, int nhoff,
> > udp_lookup_t lookup)
> > {
> > - __be16 newlen = htons(skb->len - nhoff);
> > struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
> > + unsigned int newlen = skb->len - nhoff;
> > struct sock *sk;
> > int err;
> >
> > - uh->len = newlen;
> > + udp_set_len_short(uh, newlen);
>
> [Severity: High]
> If gro_max_size is configured larger than 65535 (which is supported and used
> for BIG TCP), can't UDP GRO aggregate packets such that newlen > 65535?
This is the first patch that just converted direct access to helpers.
Patch 4 "udp: Support gro_ipv4_max_size > 65536" explicitly enables
len > 64k and replaces this line with udp_set_len. This comment on
patch 1 is irrelevant because it assumes that functionality added in a
later patch should work in a prior patch.
> This would instantly trigger the DEBUG_NET_WARN_ON_ONCE inside
> udp_set_len_short() for legitimate large packets.
>
> > [ ... ]
> > diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
> > index 9ab3728f9630b..0fccb38f074d2 100644
> > --- a/net/ipv4/udp_tunnel_core.c
> > +++ b/net/ipv4/udp_tunnel_core.c
> > @@ -178,7 +178,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
> >
> > uh->dest = dst_port;
> > uh->source = src_port;
> > - uh->len = htons(skb->len);
> > + udp_set_len_short(uh, skb->len);
>
> [Severity: High]
> When transmitting a TCP BIG TCP packet (which can be > 64K) over a UDP
> tunnel like VXLAN, skb->len will exceed 65535.
>
> Does using udp_set_len_short() here incorrectly trigger the warning for
> valid large GSO payloads?
Same here. This is replaced by udp_set_len, which supports len > 64k,
in the patch that actually enables len > 64k.
> > [ ... ]
> > diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
> > index 9adb5775487fa..dcff7fb16ff64 100644
> > --- a/net/ipv6/ip6_udp_tunnel.c
> > +++ b/net/ipv6/ip6_udp_tunnel.c
> > @@ -93,7 +93,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
> > uh->dest = dst_port;
> > uh->source = src_port;
> >
> > - uh->len = htons(skb->len);
> > + udp_set_len_short(uh, skb->len);
>
> [Severity: High]
> This appears to have the same issue as IPv4 tunnels. If a large GSO payload
> is sent through an IPv6 UDP tunnel, won't skb->len exceed 65535 and trigger
> the warning?
Same here.
I'm sorry, but I highly doubt that these AI review comments were validated.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO
2026-07-16 14:47 ` Simon Horman
@ 2026-07-16 16:28 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-16 16:28 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
On Thu, 16 Jul 2026 at 17:47, Simon Horman <horms@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [2]: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO ---
> commit b8199f77774400021642eb53bd60ec1a062a54ef
> Author: Alice Mikityanska <alice@isovalent.com>
>
> net: Enable BIG TCP with partial GSO
>
> This commit removes the 65534-byte clamp on segment length in skb_segment
> for partial GSO. It stores the gso_by_frags flag early to allow BIG TCP
> packets to use larger lengths without accidental resegmentation.
>
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index 18dabb4e9cfa0..6ae4c2b205f2e 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
>
> [ ... ]
>
> > @@ -4852,9 +4853,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
> > /* GSO partial only requires that we trim off any excess that
> > * doesn't fit into an MSS sized block, so take care of that
> > * now.
> > - * Cap len to not accidentally hit GSO_BY_FRAGS.
> > */
> > - partial_segs = min(len, GSO_BY_FRAGS - 1) / mss;
> > + partial_segs = len / mss;
>
> [Severity: High]
> When removing the clamp on partial GSO segments, mss is scaled up without any
> upper bound. For BIG TCP packets, could this construct segments that exceed
> MAX_SKB_FRAGS?
>
> If a 512KB packet is passed to skb_segment() for partial GSO, mss is scaled
> up to the full packet length. When attempting to build this single large
> segment by flattening the frag_list into a new frags array, it appears it
> would hit the fragment limit and abort:
>
> net/core/skbuff.c:skb_segment() {
> ...
> if (unlikely(skb_shinfo(nskb)->nr_frags >=
> MAX_SKB_FRAGS)) {
> net_warn_ratelimited(
> "skb_segment: too many frags: %u %u\n",
> pos, mss);
> err = -EINVAL;
> goto err;
> }
> ...
> }
>
> Does this deterministically drop BIG TCP traffic over tunnels that require
> partial GSO?
I already addressed this exact concern here:
https://lore.kernel.org/netdev/1cf2746f-f15b-406d-bb49-2c3f2dee1ec2@app.fastmail.com/
Key points:
1. skb_segment can fail with "too many frags" before my changes, even
without BIG TCP. It's not a new bug that my patch adds.
2. tcp_sendmsg_locked doesn't build frag_list SKBs, and non-frag_list
SKBs never fail in skb_segment with "too many frags".
3. When sending a TCP stream, 32768-byte high order pages are
allocated, so even a 512 KB SKB can be represented without frag_list
(and if such high-order allocation fails, tcp_sendmsg_locked won't use
frag_list anyway).
4. The only scenario I can think of to get "too many frags" with
partial GSO is receiving traffic and forwarding it to a partial GSO
netdev. But again, then it easily hits "too many frags" even without
BIG TCP or my changes (see the repro by the link above).
There is definitely no "deterministic drop of BIG TCP" here, because
of #2, and the selftest shows that it works.
So, I'm open to discussion on how to make skb_segment more reliable (I
wrote one idea by the link above), but I don't think it should block
this series.
> [Severity: Medium]
> Can the partial_segs calculation exceed 65535 for malicious inputs and cause
> a 16-bit truncation?
>
> If a crafted packet with a very small gso_size (for example, mss=1 via an
> untrusted packet socket) and a large payload is segmented, len / mss could
> produce a value greater than 65535.
>
> When this 32-bit value is later assigned to the 16-bit field in skb_segment():
>
> net/core/skbuff.c:skb_segment() {
> ...
> skb_shinfo(iter)->gso_segs = partial_segs;
> ...
> }
I'll clamp partial_segs to GSO_MAX_SEGS=65535 to make sure that
gso_segs doesn't overflow. Worst case, in an extreme scenario of
gso_size=1, partial GSO will produce more than 2 output SKBs, but the
traffic should still flow — this is how BIG TCP SKBs were handled by
skb_segment before this change.
This overflow shouldn't be possible with TCP, because
TCP_MIN_GSO_SIZE=8, but AI suggests that virtio_net_hdr_to_skb can
accept any gso_size, even 1, which makes such overflow possible.
> Could this silent truncation corrupt hardware engine programming or Byte Queue
> Limits?
>
> > if (partial_segs > 1)
> > mss *= partial_segs;
> > else
>
> [ ... ]
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536
2026-07-16 14:47 ` Simon Horman
@ 2026-07-16 17:04 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-16 17:04 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
On Thu, 16 Jul 2026 at 17:48, Simon Horman <horms@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [4]: [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 ---
> commit 6dfda0f76318408b2e2b33603d561940b926529c
> Author: Alice Mikityanska <alice@isovalent.com>
> Subject: udp: Support gro_ipv4_max_size > 65536
>
> This commit fixes UDP GRO aggregation for packets larger than 65536 bytes
> by setting the UDP length field to 0 during GRO and restoring the true length
> from skb->len in udp_rcv().
>
> > diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> > index 493e2b9e16fbc..4f9a3922937cc 100644
> > --- a/net/ipv4/udp_offload.c
> > +++ b/net/ipv4/udp_offload.c
> > @@ -919,7 +919,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
> > struct sock *sk;
> > int err;
> >
> > - udp_set_len_short(uh, newlen);
> > + udp_set_len(uh, newlen);
>
> [Severity: High]
> Does setting the UDP length to 0 here (for packets > 65535 bytes) break
> software segmentation?
>
> In net/ipv4/udp_offload.c:__udp_gso_segment(), the code adjusts the
> pseudo-header checksum by subtracting uh->len:
>
> check = csum16_add(csum16_sub(uh->check, uh->len), htons(newlen));
>
> If uh->len is 0 for BIG TCP packets, this subtraction will fail to remove
> the true 32-bit original length from the checksum.
I've already replied to this AI review comment before, and it's
mentioned in the cover letter. I don't get why Sashiko keeps reporting
it.
For BIG TCP inside a UDP tunnel, the SKB doesn't go to
__udp_gso_segment, but rather to __skb_udp_tunnel_segment.
> Similarly, in net/ipv4/udp_offload.c:__skb_udp_tunnel_segment(), partial
> GSO relies on uh->len to negate the old length:
>
> if (skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL)
> partial = (__force __wsum)uh->len;
> else
> partial = (__force __wsum)htonl(skb->len);
> partial = csum_sub(csum_unfold(uh->check), partial);
>
> Will forwarding BIG TCP over UDP packets that fall back to software
> segmentation result in corrupted checksums for all generated segments?
No, and it's verified by the selftest that also covers csum offload off now.
Normally, gso_type for tunneled BIG TCP packets won't have
SKB_GSO_PARTIAL set, because udp_gro_complete replaces gso_type with
either SKB_GSO_UDP_TUNNEL_CSUM or SKB_GSO_UDP_TUNNEL. This way, we'll
get to the correct branch and subtract skb->len. SKB_GSO_PARTIAL is
only set by skb_segment, which is called after this check. In some
very convoluted hypothetical scenario, if we have to reenter
__skb_udp_tunnel_segment for the second time, this time with
SKB_GSO_PARTIAL, it will still be correct to take uh->len this time,
because partial GSO packets have a UDP length set to wire MSS.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive
2026-07-16 14:48 ` Simon Horman
@ 2026-07-16 18:32 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-16 18:32 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
On Thu, 16 Jul 2026 at 17:48, Simon Horman <horms@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [5]: [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive ---
> commit f1316d873c7549e0a49dc98d7614be1dc5b0f66c
> Author: Alice Mikityanska <alice@isovalent.com>
>
> udp: Validate UDP length in udp_gro_receive
>
> This patch adds an early check for malformed or padded UDP packets with
> len=0 at udp_gro_receive to exclude them from GRO, moving the check out of
> udp_gro_receive_segment.
>
> > diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
> > index 4f9a3922937cc..8f77c8788f6db 100644
> > --- a/net/ipv4/udp_offload.c
> > +++ b/net/ipv4/udp_offload.c
>
> [ ... ]
>
> > @@ -782,8 +778,14 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
> > struct sk_buff *p;
> > struct udphdr *uh2;
> > unsigned int off = skb_gro_offset(skb);
> > + unsigned int ulen;
> > int flush = 1;
> >
> > + /* Do not deal with padded or malicious packets, sorry! */
> > + ulen = udp_get_len_short(uh);
> > + if (ulen <= sizeof(*uh) || ulen != skb_gro_len(skb))
> > + goto out;
> > +
>
> [Severity: High]
> Could this early return bypass inner GRO flow matching for padded UDP tunnel
> packets?
>
> When a padded UDP tunnel packet, such as a small TCP ACK inside VXLAN or
> GENEVE, arrives in net/ipv4/udp_offload.c:udp_gro_receive() while previous
> packets of the same inner flow are held in the GRO list, the
> ulen != skb_gro_len(skb) check evaluates to true and triggers the goto out.
Min Ethernet payload size is 46 bytes. Outer IP (20) + UDP (8) + VXLAN
(8) + inner Ethernet (14) + inner IP (20) + inner TCP (20) is already
way bigger than 46, so "a small TCP ACK inside VXLAN" won't be padded.
This check should only trigger on actual malformed packets.
> Because the goto out path yields pp = NULL and flush = 1, dev_gro_receive()
> passes the new padded packet to the network stack immediately, leaving older
> packets stuck in the GRO list.
The early return does bypass inner GRO matching, but it does not
normally deliver the packet immediately. We call skb_gro_flush_final,
marking the current skb for flushing. dev_gro_receive then classifies
it as GRO_NORMAL, and gro_normal_one queues it on gro->rx_list. At
NAPI flush, gro_flush_normal first flushes held GRO aggregates, then
submits the normal list, preserving order in the normal case.
Of course, gro_normal_one might submit the normal list early, if
gro_normal_batch is reached, but it's an edge case, and we are talking
about receiving malformed/padded packets, not something that should
normally occur in high-performance TCP traffic.
> Before this change,
...the same flush mechanism was used for UDP GRO packets, when a
malformed one occurred. It could hit the same edge case (when
gro_normal_batch is reached), and reordering is more unpleasant for
UDP.
> the packet would reach inner GRO handlers (like
> tcp4_gro_receive()) which would detect the sequence or padding mismatch,
The inner TCP handler won't detect padding at the outer UDP layer, it
would be done in inet_gro_receive, which will mark the packet for
flush.
> set flush = 1, and return the held packet via pp = p. This ensured older
> packets were flushed to the stack before the new padded packet, preserving
> delivery order.
If this edge case is important, I can send a follow-up that addresses
both the existing case (UDP GRO) and the new case (TCP in UDP tunnel)
by separating ulen > skb_gro_len and sizeof(*uh) <= ulen < skb_gro_len
cases. In the latter case, I can mark the SKB for flush, but proceed
with the inner GRO handlers, so that they could return the held
aggregate via pp.
> Will bypassing this inner flow matching lead to out-of-order delivery for
> the inner protocol, resulting in duplicate ACKs and throughput degradation?
>
> > /* We can do L4 aggregation only if the packet can't land in a tunnel
> > * otherwise we could corrupt the inner stream. Detecting such packets
> > * cannot be foolproof and the aggregation might still happen in some
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v9 8/9] geneve: Enable BIG TCP packets
2026-07-16 14:48 ` Simon Horman
@ 2026-07-16 18:45 ` Alice Mikityanska
0 siblings, 0 replies; 23+ messages in thread
From: Alice Mikityanska @ 2026-07-16 18:45 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
On Thu, 16 Jul 2026 at 17:48, Simon Horman <horms@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [8]: [PATCH net-next v9 8/9] geneve: Enable BIG TCP packets ---
> commit d560b2b7c8bd97bea9e23790fdfc21cfe031b961
> Author: Alice Mikityanska <alice@isovalent.com>
>
> geneve: Enable BIG TCP packets
>
> In Cilium we do support BIG TCP, but so far the latter has only been
> enabled for direct routing use-cases. A lot of users rely on Cilium
> with vxlan/geneve tunneling though. The underlying kernel infra for
> tunneling has not been supporting BIG TCP up to this point.
>
> > diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> > index 011bf9d833caf..a1639ad53077e 100644
> > --- a/drivers/net/geneve.c
> > +++ b/drivers/net/geneve.c
> > @@ -1745,6 +1745,8 @@ static void geneve_setup(struct net_device *dev)
> > dev->max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len;
> >
> > netif_keep_dst(dev);
> > + netif_set_tso_max_size(dev, GSO_MAX_SIZE);
> > +
>
> [Severity: High]
> This is a pre-existing issue, but by enabling BIG TCP on Geneve, will it
> expose a bug where valid BIG TCP packets are incorrectly dropped?
BIG TCP on Geneve is not broken (and the selftest shows that), but see below...
> In geneve_post_decap_hint(), there is a legacy size check that rejects
> packets aggregated by GRO to sizes >= 65536 bytes:
>
> drivers/net/geneve.c:geneve_post_decap_hint() {
> ...
> total_len = skb->len - gro_hint->nested_nh_offset;
> if (total_len >= GRO_LEGACY_MAX_SIZE)
> return -E2BIG;
> ...
> }
>
> When BIG TCP is enabled and the Geneve tunnel is configured with gro_hint,
> large flows are aggregated by GRO into packets exceeding 64KB. This will hit
> the legacy check and return -E2BIG, causing packet loss for large flows.
...This concern looks valid: in the double Geneve setup with gro_hint
enabled BIG TCP aggregate packets will be dropped.
Since this is an incompatibility between two opt-in features (BIG TCP
and GRO hint), which doesn't affect single Geneve, can it be addressed
in a follow-up? I can see how geneve_post_decap_hint may be altered,
but it sure needs testing.
Thanks,
Alice
> > dev->priv_flags &= ~IFF_TX_SKB_SHARING;
> > dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
> > dev->lltx = true;
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-07-16 18:45 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10 13:42 [PATCH net-next v9 0/9] BIG TCP for UDP tunnels Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 1/9] net: Use helpers to get/set UDP len tree-wide Alice Mikityanska
2026-07-16 14:46 ` Simon Horman
2026-07-16 15:18 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO Alice Mikityanska
2026-07-16 14:47 ` Simon Horman
2026-07-16 16:28 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 3/9] udp: Support BIG TCP GSO packets where they can occur Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 4/9] udp: Support gro_ipv4_max_size > 65536 Alice Mikityanska
2026-07-16 14:47 ` Simon Horman
2026-07-16 17:04 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 5/9] udp: Validate UDP length in udp_gro_receive Alice Mikityanska
2026-07-16 14:48 ` Simon Horman
2026-07-16 18:32 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 6/9] udp: Set length in UDP header to 0 for big GSO packets Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 7/9] vxlan: Enable BIG TCP packets Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 8/9] geneve: " Alice Mikityanska
2026-07-16 14:48 ` Simon Horman
2026-07-16 18:45 ` Alice Mikityanska
2026-07-10 13:42 ` [PATCH net-next v9 9/9] selftests: net: Add a test for BIG TCP in UDP tunnels Alice Mikityanska
2026-07-11 9:47 ` [PATCH net-next v9 0/9] BIG TCP for " Nikolay Aleksandrov
2026-07-15 6:11 ` zebang.li
[not found] ` <(raw)>
2026-07-15 9:06 ` Alice Mikityanska
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.