1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2024 Meta 3 4 #include "vmlinux.h" 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_core_read.h> 7 #include <bpf/bpf_endian.h> 8 #include "bpf_tracing_net.h" 9 #include "bpf_kfuncs.h" 10 11 #define ATTR __always_inline 12 #include "test_jhash.h" 13 14 static bool ipv6_addr_loopback(const struct in6_addr *a) 15 { 16 return (a->s6_addr32[0] | a->s6_addr32[1] | 17 a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0; 18 } 19 20 static bool ipv4_addr_loopback(__be32 a) 21 { 22 return a == bpf_ntohl(0x7f000001); 23 } 24 25 volatile const unsigned int sf; 26 volatile const unsigned int ss; 27 volatile const __u16 ports[2]; 28 unsigned int bucket[2]; 29 30 SEC("iter/tcp") 31 int iter_tcp_soreuse(struct bpf_iter__tcp *ctx) 32 { 33 struct sock *sk = (struct sock *)ctx->sk_common; 34 struct inet_hashinfo *hinfo; 35 unsigned int hash; 36 __u64 sock_cookie; 37 struct net *net; 38 int idx; 39 40 if (!sk) 41 return 0; 42 43 sock_cookie = bpf_get_socket_cookie(sk); 44 sk = bpf_core_cast(sk, struct sock); 45 if (sk->sk_family != sf || 46 (ss && sk->sk_state != ss) || 47 (sk->sk_family == AF_INET6 ? 48 !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) : 49 !ipv4_addr_loopback(sk->sk_rcv_saddr))) 50 return 0; 51 52 if (sk->sk_num == ports[0]) 53 idx = 0; 54 else if (sk->sk_num == ports[1]) 55 idx = 1; 56 else if (!ports[0] && !ports[1]) 57 idx = 0; 58 else 59 return 0; 60 61 /* bucket selection as in inet_lhash2_bucket_sk() */ 62 net = sk->sk_net.net; 63 hash = jhash2(sk->sk_v6_rcv_saddr.s6_addr32, 4, net->hash_mix); 64 hash ^= sk->sk_num; 65 hinfo = net->ipv4.tcp_death_row.hashinfo; 66 bucket[idx] = hash & hinfo->lhash2_mask; 67 bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); 68 bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie)); 69 70 return 0; 71 } 72 73 volatile const __u64 destroy_cookie; 74 75 SEC("iter/tcp") 76 int iter_tcp_destroy(struct bpf_iter__tcp *ctx) 77 { 78 struct sock_common *sk_common = (struct sock_common *)ctx->sk_common; 79 __u64 sock_cookie; 80 81 if (!sk_common) 82 return 0; 83 84 sock_cookie = bpf_get_socket_cookie(sk_common); 85 if (sock_cookie != destroy_cookie) 86 return 0; 87 88 bpf_sock_destroy(sk_common); 89 bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie)); 90 91 return 0; 92 } 93 94 #define udp_sk(ptr) container_of(ptr, struct udp_sock, inet.sk) 95 96 SEC("iter/udp") 97 int iter_udp_soreuse(struct bpf_iter__udp *ctx) 98 { 99 struct sock *sk = (struct sock *)ctx->udp_sk; 100 struct udp_table *udptable; 101 __u64 sock_cookie; 102 int idx; 103 104 if (!sk) 105 return 0; 106 107 sock_cookie = bpf_get_socket_cookie(sk); 108 sk = bpf_core_cast(sk, struct sock); 109 if (sk->sk_family != sf || 110 (sk->sk_family == AF_INET6 ? 111 !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) : 112 !ipv4_addr_loopback(sk->sk_rcv_saddr))) 113 return 0; 114 115 if (sk->sk_num == ports[0]) 116 idx = 0; 117 else if (sk->sk_num == ports[1]) 118 idx = 1; 119 else if (!ports[0] && !ports[1]) 120 idx = 0; 121 else 122 return 0; 123 124 /* bucket selection as in udp_hashslot2() */ 125 udptable = sk->sk_net.net->ipv4.udp_table; 126 bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask; 127 bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); 128 bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie)); 129 130 return 0; 131 } 132 133 char _license[] SEC("license") = "GPL"; 134