Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright (c) 2020 Cloudflare Ltd https://cloudflare.com */ |
| 3 | |
| 4 | #include <linux/skmsg.h> |
| 5 | #include <net/sock.h> |
| 6 | #include <net/udp.h> |
| 7 | |
| 8 | enum { |
| 9 | UDP_BPF_IPV4, |
| 10 | UDP_BPF_IPV6, |
| 11 | UDP_BPF_NUM_PROTS, |
| 12 | }; |
| 13 | |
| 14 | static struct proto *udpv6_prot_saved __read_mostly; |
| 15 | static DEFINE_SPINLOCK(udpv6_prot_lock); |
| 16 | static struct proto udp_bpf_prots[UDP_BPF_NUM_PROTS]; |
| 17 | |
| 18 | static void udp_bpf_rebuild_protos(struct proto *prot, const struct proto *base) |
| 19 | { |
| 20 | *prot = *base; |
| 21 | prot->unhash = sock_map_unhash; |
| 22 | prot->close = sock_map_close; |
| 23 | } |
| 24 | |
Lorenz Bauer | 7b219da | 2020-08-21 11:29:43 +0100 | [diff] [blame] | 25 | static void udp_bpf_check_v6_needs_rebuild(struct proto *ops) |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 26 | { |
Lorenz Bauer | 7b219da | 2020-08-21 11:29:43 +0100 | [diff] [blame] | 27 | if (unlikely(ops != smp_load_acquire(&udpv6_prot_saved))) { |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 28 | spin_lock_bh(&udpv6_prot_lock); |
| 29 | if (likely(ops != udpv6_prot_saved)) { |
| 30 | udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV6], ops); |
| 31 | smp_store_release(&udpv6_prot_saved, ops); |
| 32 | } |
| 33 | spin_unlock_bh(&udpv6_prot_lock); |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | static int __init udp_bpf_v4_build_proto(void) |
| 38 | { |
| 39 | udp_bpf_rebuild_protos(&udp_bpf_prots[UDP_BPF_IPV4], &udp_prot); |
| 40 | return 0; |
| 41 | } |
| 42 | core_initcall(udp_bpf_v4_build_proto); |
| 43 | |
Cong Wang | 8a59f9d | 2021-03-30 19:32:31 -0700 | [diff] [blame^] | 44 | int udp_bpf_update_proto(struct sock *sk, bool restore) |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 45 | { |
| 46 | int family = sk->sk_family == AF_INET ? UDP_BPF_IPV4 : UDP_BPF_IPV6; |
Cong Wang | 8a59f9d | 2021-03-30 19:32:31 -0700 | [diff] [blame^] | 47 | struct sk_psock *psock = sk_psock(sk); |
| 48 | |
| 49 | if (restore) { |
| 50 | sk->sk_write_space = psock->saved_write_space; |
| 51 | /* Pairs with lockless read in sk_clone_lock() */ |
| 52 | WRITE_ONCE(sk->sk_prot, psock->sk_proto); |
| 53 | return 0; |
| 54 | } |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 55 | |
Lorenz Bauer | 7b219da | 2020-08-21 11:29:43 +0100 | [diff] [blame] | 56 | if (sk->sk_family == AF_INET6) |
| 57 | udp_bpf_check_v6_needs_rebuild(psock->sk_proto); |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 58 | |
Cong Wang | 8a59f9d | 2021-03-30 19:32:31 -0700 | [diff] [blame^] | 59 | /* Pairs with lockless read in sk_clone_lock() */ |
| 60 | WRITE_ONCE(sk->sk_prot, &udp_bpf_prots[family]); |
| 61 | return 0; |
Lorenz Bauer | edc6741c | 2020-03-09 11:12:38 +0000 | [diff] [blame] | 62 | } |
Cong Wang | 8a59f9d | 2021-03-30 19:32:31 -0700 | [diff] [blame^] | 63 | EXPORT_SYMBOL_GPL(udp_bpf_update_proto); |