[openwrt/openwrt] kernel: fix UDPv6 GSO segmentation with NAT
LEDE Commits
lede-commits at lists.infradead.org
Sat Apr 26 11:54:03 PDT 2025
nbd pushed a commit to openwrt/openwrt.git, branch openwrt-24.10:
https://git.openwrt.org/0b392b925fa16c40dccc487753a4412bd054cd63
commit 0b392b925fa16c40dccc487753a4412bd054cd63
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Sat Apr 26 19:10:54 2025 +0200
kernel: fix UDPv6 GSO segmentation with NAT
Fixes issues with rx-gro-list and NAT66
Fixes: https://github.com/openwrt/openwrt/issues/18387
Fixes: https://github.com/openwrt/openwrt/issues/18516
Fixes: https://github.com/openwrt/openwrt/issues/18608
Signed-off-by: Felix Fietkau <nbd at nbd.name>
(cherry picked from commit 5501a502e499e0202bdfd0feebbbedb012d5f82b)
---
...-ipv6-fix-UDPv6-GSO-segmentation-with-NAT.patch | 88 ++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/target/linux/generic/pending-6.6/691-net-ipv6-fix-UDPv6-GSO-segmentation-with-NAT.patch b/target/linux/generic/pending-6.6/691-net-ipv6-fix-UDPv6-GSO-segmentation-with-NAT.patch
new file mode 100644
index 0000000000..6bbe2ca880
--- /dev/null
+++ b/target/linux/generic/pending-6.6/691-net-ipv6-fix-UDPv6-GSO-segmentation-with-NAT.patch
@@ -0,0 +1,88 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Sat, 26 Apr 2025 17:18:03 +0200
+Subject: [PATCH] net: ipv6: fix UDPv6 GSO segmentation with NAT
+
+If any address or port is changed, update it in all packets and recalculate
+checksum.
+
+Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segme
+ return segs;
+ }
+
++static void __udpv6_gso_segment_csum(struct sk_buff *seg,
++ struct in6_addr *oldip,
++ const struct in6_addr *newip,
++ __be16 *oldport, __be16 newport)
++{
++ struct udphdr *uh = udp_hdr(seg);
++
++ if (ipv6_addr_equal(oldip, newip) && *oldport == newport)
++ return;
++
++ if (uh->check) {
++ inet_proto_csum_replace16(&uh->check, seg, oldip->s6_addr32,
++ newip->s6_addr32, true);
++
++ inet_proto_csum_replace2(&uh->check, seg, *oldport, newport,
++ false);
++ if (!uh->check)
++ uh->check = CSUM_MANGLED_0;
++ }
++
++ *oldip = *newip;
++ *oldport = newport;
++}
++
++static struct sk_buff *__udpv6_gso_segment_list_csum(struct sk_buff *segs)
++{
++ const struct ipv6hdr *iph;
++ const struct udphdr *uh;
++ struct ipv6hdr *iph2;
++ struct sk_buff *seg;
++ struct udphdr *uh2;
++
++ seg = segs;
++ uh = udp_hdr(seg);
++ iph = ipv6_hdr(seg);
++ uh2 = udp_hdr(seg->next);
++ iph2 = ipv6_hdr(seg->next);
++
++ if (!(*(const u32 *)&uh->source ^ *(const u32 *)&uh2->source) &&
++ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
++ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
++ return segs;
++
++ while ((seg = seg->next)) {
++ uh2 = udp_hdr(seg);
++ iph2 = ipv6_hdr(seg);
++
++ __udpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr,
++ &uh2->source, uh->source);
++ __udpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr,
++ &uh2->dest, uh->dest);
++ }
++
++ return segs;
++}
++
+ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
+ netdev_features_t features,
+ bool is_ipv6)
+@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment
+
+ udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
+
+- return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
++ if (is_ipv6)
++ return __udpv6_gso_segment_list_csum(skb);
++ else
++ return __udpv4_gso_segment_list_csum(skb);
+ }
+
+ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
More information about the lede-commits
mailing list