Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Return socket cookies from sock_iter_batch progs

Extend the iter_udp_soreuse and iter_tcp_soreuse programs to write the
cookie of the current socket, so that we can track the identity of the
sockets that the iterator has seen so far. Update the existing do_test
function to account for this change to the iterator program output. At
the same time, teach both programs to work with AF_INET as well.

Signed-off-by: Jordan Rife <jordan@jrife.io>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

authored by

Jordan Rife and committed by
Martin KaFai Lau
4a0614e1 5668f73f

+41 -17
+20 -13
tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c
··· 9 9 10 10 static const int nr_soreuse = 4; 11 11 12 + struct iter_out { 13 + int idx; 14 + __u64 cookie; 15 + } __packed; 16 + 12 17 static void do_test(int sock_type, bool onebyone) 13 18 { 14 19 int err, i, nread, to_read, total_read, iter_fd = -1; 15 - int first_idx, second_idx, indices[nr_soreuse]; 20 + struct iter_out outputs[nr_soreuse]; 16 21 struct bpf_link *link = NULL; 17 22 struct sock_iter_batch *skel; 23 + int first_idx, second_idx; 18 24 int *fds[2] = {}; 19 25 20 26 skel = sock_iter_batch__open(); ··· 40 34 goto done; 41 35 skel->rodata->ports[i] = ntohs(local_port); 42 36 } 37 + skel->rodata->sf = AF_INET6; 43 38 44 39 err = sock_iter_batch__load(skel); 45 40 if (!ASSERT_OK(err, "sock_iter_batch__load")) ··· 62 55 * from a bucket and leave one socket out from 63 56 * that bucket on purpose. 64 57 */ 65 - to_read = (nr_soreuse - 1) * sizeof(*indices); 58 + to_read = (nr_soreuse - 1) * sizeof(*outputs); 66 59 total_read = 0; 67 60 first_idx = -1; 68 61 do { 69 - nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read); 70 - if (nread <= 0 || nread % sizeof(*indices)) 62 + nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read); 63 + if (nread <= 0 || nread % sizeof(*outputs)) 71 64 break; 72 65 total_read += nread; 73 66 74 67 if (first_idx == -1) 75 - first_idx = indices[0]; 76 - for (i = 0; i < nread / sizeof(*indices); i++) 77 - ASSERT_EQ(indices[i], first_idx, "first_idx"); 68 + first_idx = outputs[0].idx; 69 + for (i = 0; i < nread / sizeof(*outputs); i++) 70 + ASSERT_EQ(outputs[i].idx, first_idx, "first_idx"); 78 71 } while (total_read < to_read); 79 - ASSERT_EQ(nread, onebyone ? sizeof(*indices) : to_read, "nread"); 72 + ASSERT_EQ(nread, onebyone ? sizeof(*outputs) : to_read, "nread"); 80 73 ASSERT_EQ(total_read, to_read, "total_read"); 81 74 82 75 free_fds(fds[first_idx], nr_soreuse); 83 76 fds[first_idx] = NULL; 84 77 85 78 /* Read the "whole" second bucket */ 86 - to_read = nr_soreuse * sizeof(*indices); 79 + to_read = nr_soreuse * sizeof(*outputs); 87 80 total_read = 0; 88 81 second_idx = !first_idx; 89 82 do { 90 - nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read); 91 - if (nread <= 0 || nread % sizeof(*indices)) 83 + nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read); 84 + if (nread <= 0 || nread % sizeof(*outputs)) 92 85 break; 93 86 total_read += nread; 94 87 95 - for (i = 0; i < nread / sizeof(*indices); i++) 96 - ASSERT_EQ(indices[i], second_idx, "second_idx"); 88 + for (i = 0; i < nread / sizeof(*outputs); i++) 89 + ASSERT_EQ(outputs[i].idx, second_idx, "second_idx"); 97 90 } while (total_read <= to_read); 98 91 ASSERT_EQ(nread, 0, "nread"); 99 92 /* Both so_reuseport ports should be in different buckets, so
+1
tools/testing/selftests/bpf/progs/bpf_tracing_net.h
··· 128 128 #define sk_refcnt __sk_common.skc_refcnt 129 129 #define sk_state __sk_common.skc_state 130 130 #define sk_net __sk_common.skc_net 131 + #define sk_rcv_saddr __sk_common.skc_rcv_saddr 131 132 #define sk_v6_daddr __sk_common.skc_v6_daddr 132 133 #define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr 133 134 #define sk_flags __sk_common.skc_flags
+20 -4
tools/testing/selftests/bpf/progs/sock_iter_batch.c
··· 17 17 a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0; 18 18 } 19 19 20 + static bool ipv4_addr_loopback(__be32 a) 21 + { 22 + return a == bpf_ntohl(0x7f000001); 23 + } 24 + 25 + volatile const unsigned int sf; 20 26 volatile const __u16 ports[2]; 21 27 unsigned int bucket[2]; 22 28 ··· 32 26 struct sock *sk = (struct sock *)ctx->sk_common; 33 27 struct inet_hashinfo *hinfo; 34 28 unsigned int hash; 29 + __u64 sock_cookie; 35 30 struct net *net; 36 31 int idx; 37 32 38 33 if (!sk) 39 34 return 0; 40 35 36 + sock_cookie = bpf_get_socket_cookie(sk); 41 37 sk = bpf_core_cast(sk, struct sock); 42 - if (sk->sk_family != AF_INET6 || 38 + if (sk->sk_family != sf || 43 39 sk->sk_state != TCP_LISTEN || 44 - !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) 40 + sk->sk_family == AF_INET6 ? 41 + !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) : 42 + !ipv4_addr_loopback(sk->sk_rcv_saddr)) 45 43 return 0; 46 44 47 45 if (sk->sk_num == ports[0]) ··· 62 52 hinfo = net->ipv4.tcp_death_row.hashinfo; 63 53 bucket[idx] = hash & hinfo->lhash2_mask; 64 54 bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); 55 + bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie)); 65 56 66 57 return 0; 67 58 } ··· 74 63 { 75 64 struct sock *sk = (struct sock *)ctx->udp_sk; 76 65 struct udp_table *udptable; 66 + __u64 sock_cookie; 77 67 int idx; 78 68 79 69 if (!sk) 80 70 return 0; 81 71 72 + sock_cookie = bpf_get_socket_cookie(sk); 82 73 sk = bpf_core_cast(sk, struct sock); 83 - if (sk->sk_family != AF_INET6 || 84 - !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr)) 74 + if (sk->sk_family != sf || 75 + sk->sk_family == AF_INET6 ? 76 + !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) : 77 + !ipv4_addr_loopback(sk->sk_rcv_saddr)) 85 78 return 0; 86 79 87 80 if (sk->sk_num == ports[0]) ··· 99 84 udptable = sk->sk_net.net->ipv4.udp_table; 100 85 bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask; 101 86 bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx)); 87 + bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie)); 102 88 103 89 return 0; 104 90 }