f2fs-clean-up-unnecessary-indentation.patch
f2fs-prevent-the-current-section-from-being-selected.patch
f2fs-fix-to-do-sanity-check-on-sbi-total_valid_block.patch
-udp_tunnel-create-a-fastpath-gro-lookup.patch
-udp_tunnel-use-static-call-for-gro-hooks-when-possib.patch
-udp-properly-deal-with-xfrm-encap-and-addrform.patch
page_pool-move-pp_magic-check-into-helper-functions.patch
page_pool-track-dma-mapped-pages-and-unmap-them-when.patch
net-mlx5-hws-fix-matcher-action-template-attach.patch
+++ /dev/null
-From 7379d064b4e3a412604ed33592bdaee2468b6c95 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 9 Apr 2025 22:00:56 +0200
-Subject: udp: properly deal with xfrm encap and ADDRFORM
-
-From: Paolo Abeni <pabeni@redhat.com>
-
-[ Upstream commit c26c192c3d486a2a7d83d254bae294c2f8f50abf ]
-
-UDP GRO accounting assumes that the GRO receive callback is always
-set when the UDP tunnel is enabled, but syzkaller proved otherwise,
-leading tot the following splat:
-
-WARNING: CPU: 0 PID: 5837 at net/ipv4/udp_offload.c:123 udp_tunnel_update_gro_rcv+0x28d/0x4c0 net/ipv4/udp_offload.c:123
-Modules linked in:
-CPU: 0 UID: 0 PID: 5837 Comm: syz-executor850 Not tainted 6.14.0-syzkaller-13320-g420aabef3ab5 #0 PREEMPT(full)
-Hardware name: Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2025
-RIP: 0010:udp_tunnel_update_gro_rcv+0x28d/0x4c0 net/ipv4/udp_offload.c:123
-Code: 00 00 e8 c6 5a 2f f7 48 c1 e5 04 48 8d b5 20 53 c7 9a ba 10
- 00 00 00 4c 89 ff e8 ce 87 99 f7 e9 ce 00 00 00 e8 a4 5a 2f
- f7 90 <0f> 0b 90 e9 de fd ff ff bf 01 00 00 00 89 ee e8 cf
- 5e 2f f7 85 ed
-RSP: 0018:ffffc90003effa88 EFLAGS: 00010293
-RAX: ffffffff8a93fc9c RBX: 0000000000000000 RCX: ffff8880306f9e00
-RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
-RBP: 0000000000000000 R08: ffffffff8a93fabe R09: 1ffffffff20bfb2e
-R10: dffffc0000000000 R11: fffffbfff20bfb2f R12: ffff88814ef21738
-R13: dffffc0000000000 R14: ffff88814ef21778 R15: 1ffff11029de42ef
-FS: 0000000000000000(0000) GS:ffff888124f96000(0000) knlGS:0000000000000000
-CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
-CR2: 00007f04eec760d0 CR3: 000000000eb38000 CR4: 00000000003526f0
-DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
-DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
-Call Trace:
- <TASK>
- udp_tunnel_cleanup_gro include/net/udp_tunnel.h:205 [inline]
- udpv6_destroy_sock+0x212/0x270 net/ipv6/udp.c:1829
- sk_common_release+0x71/0x2e0 net/core/sock.c:3896
- inet_release+0x17d/0x200 net/ipv4/af_inet.c:435
- __sock_release net/socket.c:647 [inline]
- sock_close+0xbc/0x240 net/socket.c:1391
- __fput+0x3e9/0x9f0 fs/file_table.c:465
- task_work_run+0x251/0x310 kernel/task_work.c:227
- exit_task_work include/linux/task_work.h:40 [inline]
- do_exit+0xa11/0x27f0 kernel/exit.c:953
- do_group_exit+0x207/0x2c0 kernel/exit.c:1102
- __do_sys_exit_group kernel/exit.c:1113 [inline]
- __se_sys_exit_group kernel/exit.c:1111 [inline]
- __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1111
- x64_sys_call+0x26c3/0x26d0 arch/x86/include/generated/asm/syscalls_64.h:232
- do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
- do_syscall_64+0xf3/0x230 arch/x86/entry/syscall_64.c:94
- entry_SYSCALL_64_after_hwframe+0x77/0x7f
-RIP: 0033:0x7f04eebfac79
-Code: Unable to access opcode bytes at 0x7f04eebfac4f.
-RSP: 002b:00007fffdcaa34a8 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
-RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f04eebfac79
-RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000000
-RBP: 00007f04eec75270 R08: ffffffffffffffb8 R09: 00007fffdcaa36c8
-R10: 0000200000000000 R11: 0000000000000246 R12: 00007f04eec75270
-R13: 0000000000000000 R14: 00007f04eec75cc0 R15: 00007f04eebcca70
-
-Address the issue moving the accounting hook into
-setup_udp_tunnel_sock() and set_xfrm_gro_udp_encap_rcv(), where
-the GRO callback is actually set.
-
-set_xfrm_gro_udp_encap_rcv() is prone to races with IPV6_ADDRFORM,
-run the relevant setsockopt under the socket lock to ensure using
-consistent values of sk_family and up->encap_type.
-
-Refactor the GRO callback selection code, to make it clear that
-the function pointer is always initialized.
-
-Reported-by: syzbot+8c469a2260132cd095c1@syzkaller.appspotmail.com
-Closes: https://syzkaller.appspot.com/bug?extid=8c469a2260132cd095c1
-Fixes: 172bf009c18d ("xfrm: Support GRO for IPv4 ESP in UDP encapsulation")
-Fixes: 5d7f5b2f6b935 ("udp_tunnel: use static call for GRO hooks when possible")
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
-Link: https://patch.msgid.link/92bcdb6899145a9a387c8fa9e3ca656642a43634.1744228733.git.pabeni@redhat.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/udp_tunnel.h | 1 -
- net/ipv4/udp.c | 31 ++++++++++++++++++++++++++-----
- net/ipv4/udp_tunnel_core.c | 2 ++
- 3 files changed, 28 insertions(+), 6 deletions(-)
-
-diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
-index 288f06f23a804..2df3b8344eb52 100644
---- a/include/net/udp_tunnel.h
-+++ b/include/net/udp_tunnel.h
-@@ -215,7 +215,6 @@ static inline void udp_tunnel_encap_enable(struct sock *sk)
- if (READ_ONCE(sk->sk_family) == PF_INET6)
- ipv6_stub->udpv6_encap_enable();
- #endif
-- udp_tunnel_update_gro_rcv(sk, true);
- udp_encap_enable();
- }
-
-diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
-index 04cd3353f1d46..af943b905804a 100644
---- a/net/ipv4/udp.c
-+++ b/net/ipv4/udp.c
-@@ -2904,15 +2904,33 @@ void udp_destroy_sock(struct sock *sk)
- }
- }
-
-+typedef struct sk_buff *(*udp_gro_receive_t)(struct sock *sk,
-+ struct list_head *head,
-+ struct sk_buff *skb);
-+
- static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
- struct sock *sk)
- {
- #ifdef CONFIG_XFRM
-+ udp_gro_receive_t new_gro_receive;
-+
- if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
-- if (family == AF_INET)
-- WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
-- else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
-- WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
-+ if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
-+ new_gro_receive = ipv6_stub->xfrm6_gro_udp_encap_rcv;
-+ else
-+ new_gro_receive = xfrm4_gro_udp_encap_rcv;
-+
-+ if (udp_sk(sk)->gro_receive != new_gro_receive) {
-+ /*
-+ * With IPV6_ADDRFORM the gro callback could change
-+ * after being set, unregister the old one, if valid.
-+ */
-+ if (udp_sk(sk)->gro_receive)
-+ udp_tunnel_update_gro_rcv(sk, false);
-+
-+ WRITE_ONCE(udp_sk(sk)->gro_receive, new_gro_receive);
-+ udp_tunnel_update_gro_rcv(sk, true);
-+ }
- }
- #endif
- }
-@@ -2962,6 +2980,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
- break;
-
- case UDP_ENCAP:
-+ sockopt_lock_sock(sk);
- switch (val) {
- case 0:
- #ifdef CONFIG_XFRM
-@@ -2985,6 +3004,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
- err = -ENOPROTOOPT;
- break;
- }
-+ sockopt_release_sock(sk);
- break;
-
- case UDP_NO_CHECK6_TX:
-@@ -3002,13 +3022,14 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
- break;
-
- case UDP_GRO:
--
-+ sockopt_lock_sock(sk);
- /* when enabling GRO, accept the related GSO packet type */
- if (valbool)
- udp_tunnel_encap_enable(sk);
- udp_assign_bit(GRO_ENABLED, sk, valbool);
- udp_assign_bit(ACCEPT_L4, sk, valbool);
- set_xfrm_gro_udp_encap_rcv(up->encap_type, sk->sk_family, sk);
-+ sockopt_release_sock(sk);
- break;
-
- /*
-diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
-index 3d1214e6df0ea..2326548997d3f 100644
---- a/net/ipv4/udp_tunnel_core.c
-+++ b/net/ipv4/udp_tunnel_core.c
-@@ -90,6 +90,8 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
-
- udp_tunnel_encap_enable(sk);
-
-+ udp_tunnel_update_gro_rcv(sk, true);
-+
- if (!sk->sk_dport && !sk->sk_bound_dev_if && sk_saddr_any(sk) &&
- sk->sk_kern_sock)
- udp_tunnel_update_gro_lookup(net, sk, true);
---
-2.39.5
-
+++ /dev/null
-From 57f99d8615549a5172faf93150703db31f61f6eb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 7 Apr 2025 17:45:41 +0200
-Subject: udp_tunnel: create a fastpath GRO lookup.
-
-From: Paolo Abeni <pabeni@redhat.com>
-
-[ Upstream commit a36283e2b683f172aa1760c77325e50b16c0f792 ]
-
-Most UDP tunnels bind a socket to a local port, with ANY address, no
-peer and no interface index specified.
-Additionally it's quite common to have a single tunnel device per
-namespace.
-
-Track in each namespace the UDP tunnel socket respecting the above.
-When only a single one is present, store a reference in the netns.
-
-When such reference is not NULL, UDP tunnel GRO lookup just need to
-match the incoming packet destination port vs the socket local port.
-
-The tunnel socket never sets the reuse[port] flag[s]. When bound to no
-address and interface, no other socket can exist in the same netns
-matching the specified local port.
-
-Matching packets with non-local destination addresses will be
-aggregated, and eventually segmented as needed - no behavior changes
-intended.
-
-Restrict the optimization to kernel sockets only: it covers all the
-relevant use-cases, and user-space owned sockets could be disconnected
-and rebound after setup_udp_tunnel_sock(), breaking the uniqueness
-assumption
-
-Note that the UDP tunnel socket reference is stored into struct
-netns_ipv4 for both IPv4 and IPv6 tunnels. That is intentional to keep
-all the fastpath-related netns fields in the same struct and allow
-cacheline-based optimization. Currently both the IPv4 and IPv6 socket
-pointer share the same cacheline as the `udp_table` field.
-
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-Reviewed-by: Willem de Bruijn <willemb@google.com>
-Link: https://patch.msgid.link/41d16bc8d1257d567f9344c445b4ae0b4a91ede4.1744040675.git.pabeni@redhat.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Stable-dep-of: c26c192c3d48 ("udp: properly deal with xfrm encap and ADDRFORM")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/linux/udp.h | 16 ++++++++++++++++
- include/net/netns/ipv4.h | 11 +++++++++++
- include/net/udp.h | 1 +
- include/net/udp_tunnel.h | 12 ++++++++++++
- net/ipv4/udp.c | 13 ++++++++++++-
- net/ipv4/udp_offload.c | 37 +++++++++++++++++++++++++++++++++++++
- net/ipv4/udp_tunnel_core.c | 13 +++++++++++++
- net/ipv6/udp.c | 2 ++
- net/ipv6/udp_offload.c | 5 +++++
- 9 files changed, 109 insertions(+), 1 deletion(-)
-
-diff --git a/include/linux/udp.h b/include/linux/udp.h
-index 0807e21cfec95..895240177f4f4 100644
---- a/include/linux/udp.h
-+++ b/include/linux/udp.h
-@@ -101,6 +101,13 @@ struct udp_sock {
-
- /* Cache friendly copy of sk->sk_peek_off >= 0 */
- bool peeking_with_offset;
-+
-+ /*
-+ * Accounting for the tunnel GRO fastpath.
-+ * Unprotected by compilers guard, as it uses space available in
-+ * the last UDP socket cacheline.
-+ */
-+ struct hlist_node tunnel_list;
- };
-
- #define udp_test_bit(nr, sk) \
-@@ -219,4 +226,13 @@ static inline void udp_allow_gso(struct sock *sk)
-
- #define IS_UDPLITE(__sk) (__sk->sk_protocol == IPPROTO_UDPLITE)
-
-+static inline struct sock *udp_tunnel_sk(const struct net *net, bool is_ipv6)
-+{
-+#if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+ return rcu_dereference(net->ipv4.udp_tunnel_gro[is_ipv6].sk);
-+#else
-+ return NULL;
-+#endif
-+}
-+
- #endif /* _LINUX_UDP_H */
-diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
-index 650b2dc9199f4..6373e3f17da84 100644
---- a/include/net/netns/ipv4.h
-+++ b/include/net/netns/ipv4.h
-@@ -47,6 +47,11 @@ struct sysctl_fib_multipath_hash_seed {
- };
- #endif
-
-+struct udp_tunnel_gro {
-+ struct sock __rcu *sk;
-+ struct hlist_head list;
-+};
-+
- struct netns_ipv4 {
- /* Cacheline organization can be found documented in
- * Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst.
-@@ -85,6 +90,11 @@ struct netns_ipv4 {
- struct inet_timewait_death_row tcp_death_row;
- struct udp_table *udp_table;
-
-+#if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+ /* Not in a pernet subsys because need to be available at GRO stage */
-+ struct udp_tunnel_gro udp_tunnel_gro[2];
-+#endif
-+
- #ifdef CONFIG_SYSCTL
- struct ctl_table_header *forw_hdr;
- struct ctl_table_header *frags_hdr;
-@@ -277,4 +287,5 @@ struct netns_ipv4 {
- struct hlist_head *inet_addr_lst;
- struct delayed_work addr_chk_work;
- };
-+
- #endif
-diff --git a/include/net/udp.h b/include/net/udp.h
-index 6e89520e100dc..a772510b2aa58 100644
---- a/include/net/udp.h
-+++ b/include/net/udp.h
-@@ -290,6 +290,7 @@ static inline void udp_lib_init_sock(struct sock *sk)
- struct udp_sock *up = udp_sk(sk);
-
- skb_queue_head_init(&up->reader_queue);
-+ INIT_HLIST_NODE(&up->tunnel_list);
- up->forward_threshold = sk->sk_rcvbuf >> 2;
- set_bit(SOCK_CUSTOM_SOCKOPT, &sk->sk_socket->flags);
- }
-diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
-index a93dc51f6323e..1bb2b852e90eb 100644
---- a/include/net/udp_tunnel.h
-+++ b/include/net/udp_tunnel.h
-@@ -191,6 +191,18 @@ static inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
- }
- #endif
-
-+#if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+void udp_tunnel_update_gro_lookup(struct net *net, struct sock *sk, bool add);
-+#else
-+static inline void udp_tunnel_update_gro_lookup(struct net *net,
-+ struct sock *sk, bool add) {}
-+#endif
-+
-+static inline void udp_tunnel_cleanup_gro(struct sock *sk)
-+{
-+ udp_tunnel_update_gro_lookup(sock_net(sk), sk, false);
-+}
-+
- static inline void udp_tunnel_encap_enable(struct sock *sk)
- {
- if (udp_test_and_set_bit(ENCAP_ENABLED, sk))
-diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
-index 2742cc7602bb5..04cd3353f1d46 100644
---- a/net/ipv4/udp.c
-+++ b/net/ipv4/udp.c
-@@ -2897,8 +2897,10 @@ void udp_destroy_sock(struct sock *sk)
- if (encap_destroy)
- encap_destroy(sk);
- }
-- if (udp_test_bit(ENCAP_ENABLED, sk))
-+ if (udp_test_bit(ENCAP_ENABLED, sk)) {
- static_branch_dec(&udp_encap_needed_key);
-+ udp_tunnel_cleanup_gro(sk);
-+ }
- }
- }
-
-@@ -3810,6 +3812,15 @@ static void __net_init udp_set_table(struct net *net)
-
- static int __net_init udp_pernet_init(struct net *net)
- {
-+#if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+ int i;
-+
-+ /* No tunnel is configured */
-+ for (i = 0; i < ARRAY_SIZE(net->ipv4.udp_tunnel_gro); ++i) {
-+ INIT_HLIST_HEAD(&net->ipv4.udp_tunnel_gro[i].list);
-+ RCU_INIT_POINTER(net->ipv4.udp_tunnel_gro[i].sk, NULL);
-+ }
-+#endif
- udp_sysctl_init(net);
- udp_set_table(net);
-
-diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
-index 9a8142ccbabe4..67641945ba3a3 100644
---- a/net/ipv4/udp_offload.c
-+++ b/net/ipv4/udp_offload.c
-@@ -12,6 +12,38 @@
- #include <net/udp.h>
- #include <net/protocol.h>
- #include <net/inet_common.h>
-+#include <net/udp_tunnel.h>
-+
-+#if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+static DEFINE_SPINLOCK(udp_tunnel_gro_lock);
-+
-+void udp_tunnel_update_gro_lookup(struct net *net, struct sock *sk, bool add)
-+{
-+ bool is_ipv6 = sk->sk_family == AF_INET6;
-+ struct udp_sock *tup, *up = udp_sk(sk);
-+ struct udp_tunnel_gro *udp_tunnel_gro;
-+
-+ spin_lock(&udp_tunnel_gro_lock);
-+ udp_tunnel_gro = &net->ipv4.udp_tunnel_gro[is_ipv6];
-+ if (add)
-+ hlist_add_head(&up->tunnel_list, &udp_tunnel_gro->list);
-+ else if (up->tunnel_list.pprev)
-+ hlist_del_init(&up->tunnel_list);
-+
-+ if (udp_tunnel_gro->list.first &&
-+ !udp_tunnel_gro->list.first->next) {
-+ tup = hlist_entry(udp_tunnel_gro->list.first, struct udp_sock,
-+ tunnel_list);
-+
-+ rcu_assign_pointer(udp_tunnel_gro->sk, (struct sock *)tup);
-+ } else {
-+ RCU_INIT_POINTER(udp_tunnel_gro->sk, NULL);
-+ }
-+
-+ spin_unlock(&udp_tunnel_gro_lock);
-+}
-+EXPORT_SYMBOL_GPL(udp_tunnel_update_gro_lookup);
-+#endif
-
- static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features,
-@@ -694,8 +726,13 @@ static struct sock *udp4_gro_lookup_skb(struct sk_buff *skb, __be16 sport,
- {
- const struct iphdr *iph = skb_gro_network_header(skb);
- struct net *net = dev_net_rcu(skb->dev);
-+ struct sock *sk;
- int iif, sdif;
-
-+ sk = udp_tunnel_sk(net, false);
-+ if (sk && dport == htons(sk->sk_num))
-+ return sk;
-+
- inet_get_iif_sdif(skb, &iif, &sdif);
-
- return __udp4_lib_lookup(net, iph->saddr, sport,
-diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
-index 619a53eb672da..3d1214e6df0ea 100644
---- a/net/ipv4/udp_tunnel_core.c
-+++ b/net/ipv4/udp_tunnel_core.c
-@@ -58,6 +58,15 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
- }
- EXPORT_SYMBOL(udp_sock_create4);
-
-+static bool sk_saddr_any(struct sock *sk)
-+{
-+#if IS_ENABLED(CONFIG_IPV6)
-+ return ipv6_addr_any(&sk->sk_v6_rcv_saddr);
-+#else
-+ return !sk->sk_rcv_saddr;
-+#endif
-+}
-+
- void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
- struct udp_tunnel_sock_cfg *cfg)
- {
-@@ -80,6 +89,10 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
- udp_sk(sk)->gro_complete = cfg->gro_complete;
-
- udp_tunnel_encap_enable(sk);
-+
-+ if (!sk->sk_dport && !sk->sk_bound_dev_if && sk_saddr_any(sk) &&
-+ sk->sk_kern_sock)
-+ udp_tunnel_update_gro_lookup(net, sk, true);
- }
- EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
-
-diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
-index 024458ef163c9..7317f8e053f1c 100644
---- a/net/ipv6/udp.c
-+++ b/net/ipv6/udp.c
-@@ -46,6 +46,7 @@
- #include <net/tcp_states.h>
- #include <net/ip6_checksum.h>
- #include <net/ip6_tunnel.h>
-+#include <net/udp_tunnel.h>
- #include <net/xfrm.h>
- #include <net/inet_hashtables.h>
- #include <net/inet6_hashtables.h>
-@@ -1825,6 +1826,7 @@ void udpv6_destroy_sock(struct sock *sk)
- if (udp_test_bit(ENCAP_ENABLED, sk)) {
- static_branch_dec(&udpv6_encap_needed_key);
- udp_encap_disable();
-+ udp_tunnel_cleanup_gro(sk);
- }
- }
- }
-diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
-index 404212dfc99ab..d8445ac1b2e43 100644
---- a/net/ipv6/udp_offload.c
-+++ b/net/ipv6/udp_offload.c
-@@ -118,8 +118,13 @@ static struct sock *udp6_gro_lookup_skb(struct sk_buff *skb, __be16 sport,
- {
- const struct ipv6hdr *iph = skb_gro_network_header(skb);
- struct net *net = dev_net_rcu(skb->dev);
-+ struct sock *sk;
- int iif, sdif;
-
-+ sk = udp_tunnel_sk(net, true);
-+ if (sk && dport == htons(sk->sk_num))
-+ return sk;
-+
- inet6_get_iif_sdif(skb, &iif, &sdif);
-
- return __udp6_lib_lookup(net, &iph->saddr, sport,
---
-2.39.5
-
+++ /dev/null
-From ad8d1ce2b68078680a685515600fbafbb35fa691 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 7 Apr 2025 17:45:42 +0200
-Subject: udp_tunnel: use static call for GRO hooks when possible
-
-From: Paolo Abeni <pabeni@redhat.com>
-
-[ Upstream commit 5d7f5b2f6b935517ee5fd8058dc32342a5cba3e1 ]
-
-It's quite common to have a single UDP tunnel type active in the
-whole system. In such a case we can replace the indirect call for
-the UDP tunnel GRO callback with a static call.
-
-Add the related accounting in the control path and switch to static
-call when possible. To keep the code simple use a static array for
-the registered tunnel types, and size such array based on the kernel
-config.
-
-Note that there are valid kernel configurations leading to
-UDP_MAX_TUNNEL_TYPES == 0 even with IS_ENABLED(CONFIG_NET_UDP_TUNNEL),
-Explicitly skip the accounting in such a case, to avoid compile warning
-when accessing "udp_tunnel_gro_types".
-
-Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-Reviewed-by: Willem de Bruijn <willemb@google.com>
-Link: https://patch.msgid.link/53d156cdfddcc9678449e873cc83e68fa1582653.1744040675.git.pabeni@redhat.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Stable-dep-of: c26c192c3d48 ("udp: properly deal with xfrm encap and ADDRFORM")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- include/net/udp_tunnel.h | 4 ++
- net/ipv4/udp_offload.c | 135 ++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 138 insertions(+), 1 deletion(-)
-
-diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
-index 1bb2b852e90eb..288f06f23a804 100644
---- a/include/net/udp_tunnel.h
-+++ b/include/net/udp_tunnel.h
-@@ -193,13 +193,16 @@ static inline int udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum)
-
- #if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
- void udp_tunnel_update_gro_lookup(struct net *net, struct sock *sk, bool add);
-+void udp_tunnel_update_gro_rcv(struct sock *sk, bool add);
- #else
- static inline void udp_tunnel_update_gro_lookup(struct net *net,
- struct sock *sk, bool add) {}
-+static inline void udp_tunnel_update_gro_rcv(struct sock *sk, bool add) {}
- #endif
-
- static inline void udp_tunnel_cleanup_gro(struct sock *sk)
- {
-+ udp_tunnel_update_gro_rcv(sk, false);
- udp_tunnel_update_gro_lookup(sock_net(sk), sk, false);
- }
-
-@@ -212,6 +215,7 @@ static inline void udp_tunnel_encap_enable(struct sock *sk)
- if (READ_ONCE(sk->sk_family) == PF_INET6)
- ipv6_stub->udpv6_encap_enable();
- #endif
-+ udp_tunnel_update_gro_rcv(sk, true);
- udp_encap_enable();
- }
-
-diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
-index 67641945ba3a3..9c775f8aa4385 100644
---- a/net/ipv4/udp_offload.c
-+++ b/net/ipv4/udp_offload.c
-@@ -15,6 +15,38 @@
- #include <net/udp_tunnel.h>
-
- #if IS_ENABLED(CONFIG_NET_UDP_TUNNEL)
-+
-+/*
-+ * Dummy GRO tunnel callback, exists mainly to avoid dangling/NULL
-+ * values for the udp tunnel static call.
-+ */
-+static struct sk_buff *dummy_gro_rcv(struct sock *sk,
-+ struct list_head *head,
-+ struct sk_buff *skb)
-+{
-+ NAPI_GRO_CB(skb)->flush = 1;
-+ return NULL;
-+}
-+
-+typedef struct sk_buff *(*udp_tunnel_gro_rcv_t)(struct sock *sk,
-+ struct list_head *head,
-+ struct sk_buff *skb);
-+
-+struct udp_tunnel_type_entry {
-+ udp_tunnel_gro_rcv_t gro_receive;
-+ refcount_t count;
-+};
-+
-+#define UDP_MAX_TUNNEL_TYPES (IS_ENABLED(CONFIG_GENEVE) + \
-+ IS_ENABLED(CONFIG_VXLAN) * 2 + \
-+ IS_ENABLED(CONFIG_NET_FOU) * 2 + \
-+ IS_ENABLED(CONFIG_XFRM) * 2)
-+
-+DEFINE_STATIC_CALL(udp_tunnel_gro_rcv, dummy_gro_rcv);
-+static DEFINE_STATIC_KEY_FALSE(udp_tunnel_static_call);
-+static struct mutex udp_tunnel_gro_type_lock;
-+static struct udp_tunnel_type_entry udp_tunnel_gro_types[UDP_MAX_TUNNEL_TYPES];
-+static unsigned int udp_tunnel_gro_type_nr;
- static DEFINE_SPINLOCK(udp_tunnel_gro_lock);
-
- void udp_tunnel_update_gro_lookup(struct net *net, struct sock *sk, bool add)
-@@ -43,6 +75,105 @@ void udp_tunnel_update_gro_lookup(struct net *net, struct sock *sk, bool add)
- spin_unlock(&udp_tunnel_gro_lock);
- }
- EXPORT_SYMBOL_GPL(udp_tunnel_update_gro_lookup);
-+
-+void udp_tunnel_update_gro_rcv(struct sock *sk, bool add)
-+{
-+ struct udp_tunnel_type_entry *cur = NULL;
-+ struct udp_sock *up = udp_sk(sk);
-+ int i, old_gro_type_nr;
-+
-+ if (!UDP_MAX_TUNNEL_TYPES || !up->gro_receive)
-+ return;
-+
-+ mutex_lock(&udp_tunnel_gro_type_lock);
-+
-+ /* Check if the static call is permanently disabled. */
-+ if (udp_tunnel_gro_type_nr > UDP_MAX_TUNNEL_TYPES)
-+ goto out;
-+
-+ for (i = 0; i < udp_tunnel_gro_type_nr; i++)
-+ if (udp_tunnel_gro_types[i].gro_receive == up->gro_receive)
-+ cur = &udp_tunnel_gro_types[i];
-+
-+ old_gro_type_nr = udp_tunnel_gro_type_nr;
-+ if (add) {
-+ /*
-+ * Update the matching entry, if found, or add a new one
-+ * if needed
-+ */
-+ if (cur) {
-+ refcount_inc(&cur->count);
-+ goto out;
-+ }
-+
-+ if (unlikely(udp_tunnel_gro_type_nr == UDP_MAX_TUNNEL_TYPES)) {
-+ pr_err_once("Too many UDP tunnel types, please increase UDP_MAX_TUNNEL_TYPES\n");
-+ /* Ensure static call will never be enabled */
-+ udp_tunnel_gro_type_nr = UDP_MAX_TUNNEL_TYPES + 1;
-+ } else {
-+ cur = &udp_tunnel_gro_types[udp_tunnel_gro_type_nr++];
-+ refcount_set(&cur->count, 1);
-+ cur->gro_receive = up->gro_receive;
-+ }
-+ } else {
-+ /*
-+ * The stack cleanups only successfully added tunnel, the
-+ * lookup on removal should never fail.
-+ */
-+ if (WARN_ON_ONCE(!cur))
-+ goto out;
-+
-+ if (!refcount_dec_and_test(&cur->count))
-+ goto out;
-+
-+ /* Avoid gaps, so that the enable tunnel has always id 0 */
-+ *cur = udp_tunnel_gro_types[--udp_tunnel_gro_type_nr];
-+ }
-+
-+ if (udp_tunnel_gro_type_nr == 1) {
-+ static_call_update(udp_tunnel_gro_rcv,
-+ udp_tunnel_gro_types[0].gro_receive);
-+ static_branch_enable(&udp_tunnel_static_call);
-+ } else if (old_gro_type_nr == 1) {
-+ static_branch_disable(&udp_tunnel_static_call);
-+ static_call_update(udp_tunnel_gro_rcv, dummy_gro_rcv);
-+ }
-+
-+out:
-+ mutex_unlock(&udp_tunnel_gro_type_lock);
-+}
-+EXPORT_SYMBOL_GPL(udp_tunnel_update_gro_rcv);
-+
-+static void udp_tunnel_gro_init(void)
-+{
-+ mutex_init(&udp_tunnel_gro_type_lock);
-+}
-+
-+static struct sk_buff *udp_tunnel_gro_rcv(struct sock *sk,
-+ struct list_head *head,
-+ struct sk_buff *skb)
-+{
-+ if (static_branch_likely(&udp_tunnel_static_call)) {
-+ if (unlikely(gro_recursion_inc_test(skb))) {
-+ NAPI_GRO_CB(skb)->flush |= 1;
-+ return NULL;
-+ }
-+ return static_call(udp_tunnel_gro_rcv)(sk, head, skb);
-+ }
-+ return call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
-+}
-+
-+#else
-+
-+static void udp_tunnel_gro_init(void) {}
-+
-+static struct sk_buff *udp_tunnel_gro_rcv(struct sock *sk,
-+ struct list_head *head,
-+ struct sk_buff *skb)
-+{
-+ return call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
-+}
-+
- #endif
-
- static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
-@@ -713,7 +844,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
-
- skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
- skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
-- pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
-+ pp = udp_tunnel_gro_rcv(sk, head, skb);
-
- out:
- skb_gro_flush_final(skb, pp, flush);
-@@ -863,5 +994,7 @@ int __init udpv4_offload_init(void)
- .gro_complete = udp4_gro_complete,
- },
- };
-+
-+ udp_tunnel_gro_init();
- return inet_add_offload(&net_hotdata.udpv4_offload, IPPROTO_UDP);
- }
---
-2.39.5
-