18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Cloudflare Ltd https://cloudflare.com */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/skmsg.h> 58c2ecf20Sopenharmony_ci#include <net/sock.h> 68c2ecf20Sopenharmony_ci#include <net/udp.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_cienum { 98c2ecf20Sopenharmony_ci UDP_BPF_IPV4, 108c2ecf20Sopenharmony_ci UDP_BPF_IPV6, 118c2ecf20Sopenharmony_ci UDP_BPF_NUM_PROTS, 128c2ecf20Sopenharmony_ci}; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic struct proto *udpv6_prot_saved __read_mostly; 158c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(udpv6_prot_lock); 168c2ecf20Sopenharmony_cistatic struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci *prot = *base; 218c2ecf20Sopenharmony_ci prot->unhash = sock_map_unhash; 228c2ecf20Sopenharmony_ci prot->close = sock_map_close; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void udp_bpf_check_v6_needs_rebuild(struct proto *ops) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (unlikely(ops != smp_load_acquire(&udpv6_prot_saved))) { 288c2ecf20Sopenharmony_ci spin_lock_bh(&udpv6_prot_lock); 298c2ecf20Sopenharmony_ci if (likely(ops != udpv6_prot_saved)) { 308c2ecf20Sopenharmony_ci udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV6], ops); 318c2ecf20Sopenharmony_ci smp_store_release(&udpv6_prot_saved, ops); 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci spin_unlock_bh(&udpv6_prot_lock); 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int __init udp_bpf_v4_build_proto(void) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV4], &udp_prot); 408c2ecf20Sopenharmony_ci return 0; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_cilate_initcall(udp_bpf_v4_build_proto); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct proto *udp_bpf_get_proto(struct sock *sk, struct sk_psock *psock) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int family = sk->sk_family == AF_INET ? UDP_BPF_IPV4 : UDP_BPF_IPV6; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (sk->sk_family == AF_INET6) 498c2ecf20Sopenharmony_ci udp_bpf_check_v6_needs_rebuild(psock->sk_proto); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return &udp_bpf_prots[family]; 528c2ecf20Sopenharmony_ci} 53