]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: add sockopt tests for TCP_BPF_SOCK_OPS_CB_FLAGS
authorAlan Maguire <alan.maguire@oracle.com>
Thu, 8 Aug 2024 15:05:58 +0000 (16:05 +0100)
committerMartin KaFai Lau <martin.lau@kernel.org>
Fri, 9 Aug 2024 00:03:40 +0000 (17:03 -0700)
Add tests to set TCP sockopt TCP_BPF_SOCK_OPS_CB_FLAGS via
bpf_setsockopt() and use a cgroup/getsockopt program to retrieve
the value to verify it was set.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Link: https://lore.kernel.org/r/20240808150558.1035626-3-alan.maguire@oracle.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
tools/testing/selftests/bpf/prog_tests/setget_sockopt.c
tools/testing/selftests/bpf/progs/setget_sockopt.c

index 7d4a9b3d3722be4a9e1a37a350cbef8149f6e67b..e12255121c15c5cf61c7147c6a3937f6c2545624 100644 (file)
@@ -154,6 +154,51 @@ err_out:
        close(sfd);
 }
 
+static void test_nonstandard_opt(int family)
+{
+       struct setget_sockopt__bss *bss = skel->bss;
+       struct bpf_link *getsockopt_link = NULL;
+       int sfd = -1, fd = -1, cfd = -1, flags;
+       socklen_t flagslen = sizeof(flags);
+
+       memset(bss, 0, sizeof(*bss));
+
+       sfd = start_server(family, SOCK_STREAM,
+                          family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
+       if (!ASSERT_GE(sfd, 0, "start_server"))
+               return;
+
+       fd = connect_to_fd(sfd, 0);
+       if (!ASSERT_GE(fd, 0, "connect_to_fd_server"))
+               goto err_out;
+
+       /* cgroup/getsockopt prog will intercept getsockopt() below and
+        * retrieve the tcp socket bpf_sock_ops_cb_flags value for the
+        * accept()ed socket; this was set earlier in the passive established
+        * callback for the accept()ed socket via bpf_setsockopt().
+        */
+       getsockopt_link = bpf_program__attach_cgroup(skel->progs._getsockopt, cg_fd);
+       if (!ASSERT_OK_PTR(getsockopt_link, "getsockopt prog"))
+               goto err_out;
+
+       cfd = accept(sfd, NULL, 0);
+       if (!ASSERT_GE(cfd, 0, "accept"))
+               goto err_out;
+
+       if (!ASSERT_OK(getsockopt(cfd, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, &flagslen),
+                      "getsockopt_flags"))
+               goto err_out;
+       ASSERT_EQ(flags & BPF_SOCK_OPS_STATE_CB_FLAG, BPF_SOCK_OPS_STATE_CB_FLAG,
+                 "cb_flags_set");
+err_out:
+       close(sfd);
+       if (fd != -1)
+               close(fd);
+       if (cfd != -1)
+               close(cfd);
+       bpf_link__destroy(getsockopt_link);
+}
+
 void test_setget_sockopt(void)
 {
        cg_fd = test__join_cgroup(CG_NAME);
@@ -191,6 +236,8 @@ void test_setget_sockopt(void)
        test_udp(AF_INET);
        test_ktls(AF_INET6);
        test_ktls(AF_INET);
+       test_nonstandard_opt(AF_INET);
+       test_nonstandard_opt(AF_INET6);
 
 done:
        setget_sockopt__destroy(skel);
index 60518aed1ffcec80be6972860e27dc7c8d1297be..6dd4318debbfb08ccc8140e795ae653609b1d908 100644 (file)
@@ -59,6 +59,8 @@ static const struct sockopt_test sol_tcp_tests[] = {
        { .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, },
        { .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, },
        { .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, },
+       { .opt = TCP_BPF_SOCK_OPS_CB_FLAGS, .new = BPF_SOCK_OPS_ALL_CB_FLAGS,
+         .expected = BPF_SOCK_OPS_ALL_CB_FLAGS, },
        { .opt = 0, },
 };
 
@@ -353,11 +355,30 @@ int BPF_PROG(socket_post_create, struct socket *sock, int family,
        return 1;
 }
 
+SEC("cgroup/getsockopt")
+int _getsockopt(struct bpf_sockopt *ctx)
+{
+       struct bpf_sock *sk = ctx->sk;
+       int *optval = ctx->optval;
+       struct tcp_sock *tp;
+
+       if (!sk || ctx->level != SOL_TCP || ctx->optname != TCP_BPF_SOCK_OPS_CB_FLAGS)
+               return 1;
+
+       tp = bpf_core_cast(sk, struct tcp_sock);
+       if (ctx->optval + sizeof(int) <= ctx->optval_end) {
+               *optval = tp->bpf_sock_ops_cb_flags;
+               ctx->retval = 0;
+       }
+       return 1;
+}
+
 SEC("sockops")
 int skops_sockopt(struct bpf_sock_ops *skops)
 {
        struct bpf_sock *bpf_sk = skops->sk;
        struct sock *sk;
+       int flags;
 
        if (!bpf_sk)
                return 1;
@@ -384,9 +405,8 @@ int skops_sockopt(struct bpf_sock_ops *skops)
                nr_passive += !(bpf_test_sockopt(skops, sk) ||
                                test_tcp_maxseg(skops, sk) ||
                                test_tcp_saved_syn(skops, sk));
-               bpf_sock_ops_cb_flags_set(skops,
-                                         skops->bpf_sock_ops_cb_flags |
-                                         BPF_SOCK_OPS_STATE_CB_FLAG);
+               flags = skops->bpf_sock_ops_cb_flags | BPF_SOCK_OPS_STATE_CB_FLAG;
+               bpf_setsockopt(skops, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, sizeof(flags));
                break;
        case BPF_SOCK_OPS_STATE_CB:
                if (skops->args[1] == BPF_TCP_CLOSE_WAIT)