]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Return socket cookies from sock_iter_batch progs
authorJordan Rife <jordan@jrife.io>
Fri, 2 May 2025 16:15:25 +0000 (09:15 -0700)
committerMartin KaFai Lau <martin.lau@kernel.org>
Fri, 2 May 2025 19:07:53 +0000 (12:07 -0700)
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>
tools/testing/selftests/bpf/prog_tests/sock_iter_batch.c
tools/testing/selftests/bpf/progs/bpf_tracing_net.h
tools/testing/selftests/bpf/progs/sock_iter_batch.c

index d56e18b2552808fb4b48d9ada7ab3917a65b95cd..74dbe91806a027b1921a5280911f8cbafbb4631c 100644 (file)
@@ -9,12 +9,18 @@
 
 static const int nr_soreuse = 4;
 
+struct iter_out {
+       int idx;
+       __u64 cookie;
+} __packed;
+
 static void do_test(int sock_type, bool onebyone)
 {
        int err, i, nread, to_read, total_read, iter_fd = -1;
-       int first_idx, second_idx, indices[nr_soreuse];
+       struct iter_out outputs[nr_soreuse];
        struct bpf_link *link = NULL;
        struct sock_iter_batch *skel;
+       int first_idx, second_idx;
        int *fds[2] = {};
 
        skel = sock_iter_batch__open();
@@ -34,6 +40,7 @@ static void do_test(int sock_type, bool onebyone)
                        goto done;
                skel->rodata->ports[i] = ntohs(local_port);
        }
+       skel->rodata->sf = AF_INET6;
 
        err = sock_iter_batch__load(skel);
        if (!ASSERT_OK(err, "sock_iter_batch__load"))
@@ -55,38 +62,38 @@ static void do_test(int sock_type, bool onebyone)
         * from a bucket and leave one socket out from
         * that bucket on purpose.
         */
-       to_read = (nr_soreuse - 1) * sizeof(*indices);
+       to_read = (nr_soreuse - 1) * sizeof(*outputs);
        total_read = 0;
        first_idx = -1;
        do {
-               nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
-               if (nread <= 0 || nread % sizeof(*indices))
+               nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read);
+               if (nread <= 0 || nread % sizeof(*outputs))
                        break;
                total_read += nread;
 
                if (first_idx == -1)
-                       first_idx = indices[0];
-               for (i = 0; i < nread / sizeof(*indices); i++)
-                       ASSERT_EQ(indices[i], first_idx, "first_idx");
+                       first_idx = outputs[0].idx;
+               for (i = 0; i < nread / sizeof(*outputs); i++)
+                       ASSERT_EQ(outputs[i].idx, first_idx, "first_idx");
        } while (total_read < to_read);
-       ASSERT_EQ(nread, onebyone ? sizeof(*indices) : to_read, "nread");
+       ASSERT_EQ(nread, onebyone ? sizeof(*outputs) : to_read, "nread");
        ASSERT_EQ(total_read, to_read, "total_read");
 
        free_fds(fds[first_idx], nr_soreuse);
        fds[first_idx] = NULL;
 
        /* Read the "whole" second bucket */
-       to_read = nr_soreuse * sizeof(*indices);
+       to_read = nr_soreuse * sizeof(*outputs);
        total_read = 0;
        second_idx = !first_idx;
        do {
-               nread = read(iter_fd, indices, onebyone ? sizeof(*indices) : to_read);
-               if (nread <= 0 || nread % sizeof(*indices))
+               nread = read(iter_fd, outputs, onebyone ? sizeof(*outputs) : to_read);
+               if (nread <= 0 || nread % sizeof(*outputs))
                        break;
                total_read += nread;
 
-               for (i = 0; i < nread / sizeof(*indices); i++)
-                       ASSERT_EQ(indices[i], second_idx, "second_idx");
+               for (i = 0; i < nread / sizeof(*outputs); i++)
+                       ASSERT_EQ(outputs[i].idx, second_idx, "second_idx");
        } while (total_read <= to_read);
        ASSERT_EQ(nread, 0, "nread");
        /* Both so_reuseport ports should be in different buckets, so
index 659694162739ea205c9f6b53ddbe146a45dc3886..17db400f0e0d972f37e5de67c55422b2b075b8af 100644 (file)
 #define sk_refcnt              __sk_common.skc_refcnt
 #define sk_state               __sk_common.skc_state
 #define sk_net                 __sk_common.skc_net
+#define sk_rcv_saddr           __sk_common.skc_rcv_saddr
 #define sk_v6_daddr            __sk_common.skc_v6_daddr
 #define sk_v6_rcv_saddr                __sk_common.skc_v6_rcv_saddr
 #define sk_flags               __sk_common.skc_flags
index 96531b0d9d55b9ee9fcb3b70188182af7ead6e23..8f483337e103c955ea44d7109bb0ca90c4301de6 100644 (file)
@@ -17,6 +17,12 @@ static bool ipv6_addr_loopback(const struct in6_addr *a)
                a->s6_addr32[2] | (a->s6_addr32[3] ^ bpf_htonl(1))) == 0;
 }
 
+static bool ipv4_addr_loopback(__be32 a)
+{
+       return a == bpf_ntohl(0x7f000001);
+}
+
+volatile const unsigned int sf;
 volatile const __u16 ports[2];
 unsigned int bucket[2];
 
@@ -26,16 +32,20 @@ int iter_tcp_soreuse(struct bpf_iter__tcp *ctx)
        struct sock *sk = (struct sock *)ctx->sk_common;
        struct inet_hashinfo *hinfo;
        unsigned int hash;
+       __u64 sock_cookie;
        struct net *net;
        int idx;
 
        if (!sk)
                return 0;
 
+       sock_cookie = bpf_get_socket_cookie(sk);
        sk = bpf_core_cast(sk, struct sock);
-       if (sk->sk_family != AF_INET6 ||
+       if (sk->sk_family != sf ||
            sk->sk_state != TCP_LISTEN ||
-           !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
+           sk->sk_family == AF_INET6 ?
+           !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) :
+           !ipv4_addr_loopback(sk->sk_rcv_saddr))
                return 0;
 
        if (sk->sk_num == ports[0])
@@ -52,6 +62,7 @@ int iter_tcp_soreuse(struct bpf_iter__tcp *ctx)
        hinfo = net->ipv4.tcp_death_row.hashinfo;
        bucket[idx] = hash & hinfo->lhash2_mask;
        bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
+       bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie));
 
        return 0;
 }
@@ -63,14 +74,18 @@ int iter_udp_soreuse(struct bpf_iter__udp *ctx)
 {
        struct sock *sk = (struct sock *)ctx->udp_sk;
        struct udp_table *udptable;
+       __u64 sock_cookie;
        int idx;
 
        if (!sk)
                return 0;
 
+       sock_cookie = bpf_get_socket_cookie(sk);
        sk = bpf_core_cast(sk, struct sock);
-       if (sk->sk_family != AF_INET6 ||
-           !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr))
+       if (sk->sk_family != sf ||
+           sk->sk_family == AF_INET6 ?
+           !ipv6_addr_loopback(&sk->sk_v6_rcv_saddr) :
+           !ipv4_addr_loopback(sk->sk_rcv_saddr))
                return 0;
 
        if (sk->sk_num == ports[0])
@@ -84,6 +99,7 @@ int iter_udp_soreuse(struct bpf_iter__udp *ctx)
        udptable = sk->sk_net.net->ipv4.udp_table;
        bucket[idx] = udp_sk(sk)->udp_portaddr_hash & udptable->mask;
        bpf_seq_write(ctx->meta->seq, &idx, sizeof(idx));
+       bpf_seq_write(ctx->meta->seq, &sock_cookie, sizeof(sock_cookie));
 
        return 0;
 }