aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAnton Danilov <littlesmilingcloud@gmail.com>2026-07-08 03:35:03 +0300
committerPaolo Abeni <pabeni@redhat.com>2026-07-21 11:09:02 +0200
commit3cb8d4b9bfeb8a76fc895975842539aa6d5084c4 (patch)
treeab2d95512423019a67d01bf1c03b04f2a23ca265
parentMerge branch 'net-add-adin1140-support' (diff)
udp: fix encapsulation packet resubmit in multicast deliver
When a UDP encapsulation socket (e.g., FOU) receives a multicast packet, __udp4_lib_mcast_deliver() and __udp6_lib_mcast_deliver() call consume_skb() when udp_queue_rcv_skb() returns a positive value. A positive return value from udp_queue_rcv_skb() indicates that the encap_rcv handler (e.g., fou_udp_recv) has consumed the UDP header and wants the packet to be resubmitted to the IP protocol handler for further processing (e.g., as a GRE packet). The unicast paths handle this correctly by propagating the return value up to ip_protocol_deliver_rcu() / ip6_protocol_deliver_rcu() for resubmission. However, the multicast paths destroy the packet via consume_skb() instead of resubmitting it, causing silent packet loss. This affects any UDP encapsulation (FOU, GUE) combined with multicast destination addresses. Fix this by returning the value from udp_queue_rcv_skb() when it is positive, matching the behavior of the corresponding unicast paths. Note the sign difference between IPv4 and IPv6: - IPv4: udp_unicast_rcv_skb() returns -ret, and ip_protocol_deliver_rcu() resubmits when ret < 0 (using -ret as the protocol number). - IPv6: udp6_unicast_rcv_skb() returns ret, and ip6_protocol_deliver_rcu() resubmits when ret > 0 (using ret as the nexthdr). Both mcast paths now follow the same convention as their respective unicast paths. Suggested-by: Kuniyuki Iwashima <kuniyu@google.com> Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com> Assisted-by: Claude:claude-opus-4-6 Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/5372ccac062193147e02b991d5328a5c3fa3a85a.1783372173.git.littlesmilingcloud@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--net/ipv4/udp.c6
-rw-r--r--net/ipv6/udp.c6
2 files changed, 8 insertions, 4 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 59248a59358c..d3ddcbfc8477 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2476,6 +2476,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
struct udp_hslot *hslot;
struct sk_buff *nskb;
bool use_hash2;
+ int ret;
hash2_any = 0;
hash2 = 0;
@@ -2520,8 +2521,9 @@ start_lookup:
}
if (first) {
- if (udp_queue_rcv_skb(first, skb) > 0)
- consume_skb(skb);
+ ret = udp_queue_rcv_skb(first, skb);
+ if (ret > 0)
+ return -ret;
} else {
kfree_skb(skb);
__UDP_INC_STATS(net, UDP_MIB_IGNOREDMULTI);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 392e18b97045..0910cc171776 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -949,6 +949,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
struct udp_hslot *hslot;
struct sk_buff *nskb;
bool use_hash2;
+ int ret;
hash2_any = 0;
hash2 = 0;
@@ -998,8 +999,9 @@ start_lookup:
}
if (first) {
- if (udpv6_queue_rcv_skb(first, skb) > 0)
- consume_skb(skb);
+ ret = udpv6_queue_rcv_skb(first, skb);
+ if (ret > 0)
+ return ret;
} else {
kfree_skb(skb);
__UDP6_INC_STATS(net, UDP_MIB_IGNOREDMULTI);