[PATCH net-next 13/14] selftests/bpf: Test skb_ext read from sk_skb stream verdict hook
Jakub Sitnicki <[email protected]>
| Newsgroups | org.kernel.vger.bpf,org.kernel.vger.netdev |
|---|---|
| Message-ID | <20260814-bpf-meta-inside-skb-ext-v1-13-767edd862656@cloudflare.com> |
Test bpf_dynptr_from_skb_ext() from sk_skb context. Write to skb_ext from TC on loopback; read from skb_ext from the sockmap verdict program. Signed-off-by: Jakub Sitnicki <[email protected]> --- .../selftests/bpf/prog_tests/socket_helpers.h | 1 + .../bpf/prog_tests/xdp_context_test_run.c | 79 ++++++++++++++++++++++ tools/testing/selftests/bpf/progs/test_xdp_meta.c | 18 +++++ 3 files changed, 98 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h index 0d59503a0c73..eb114a6ea6f9 100644 --- a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h +++ b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h @@ -3,6 +3,7 @@ #ifndef __SOCKET_HELPERS__ #define __SOCKET_HELPERS__ +#include <error.h> #include <sys/un.h> #include <linux/vm_sockets.h> diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c index 5f9247941aa0..f5fbc19757e3 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_context_test_run.c @@ -4,6 +4,7 @@ #include <linux/ipv6.h> #include <linux/netfilter.h> #include <arpa/inet.h> +#include "socket_helpers.h" #include "test_xdp_context_test_run.skel.h" #include "test_xdp_meta.skel.h" @@ -1560,6 +1561,82 @@ static void test_skb_ext_seg6local(struct test_xdp_meta *skel) unlink(SEG6_PIN_PATH); } +/* Test skb_ext survival across TC ingress -> sk_skb verdict hook. + * TC ingress writes skb_ext on loopback; the verdict program reads it + * on skb delivery to a socket in the sockmap. + */ +static void test_skb_ext_sk_skb(struct test_xdp_meta *skel) +{ + LIBBPF_OPTS(bpf_tc_hook, tc_hook, + .ifindex = 1 /* IFINDEX_LO */, + .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); + struct bpf_link *verdict_link = NULL; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + struct netns_obj *ns = NULL; + char buf[TEST_PAYLOAD_LEN]; + int c1 = -1, p1 = -1; + int map = -1, zero = 0; + ssize_t n; + int ret; + + ns = netns_new("tc_to_sk_skb", true); + if (!ASSERT_OK_PTR(ns, "netns_new")) + return; + + skel->bss->test_pass = false; + + ret = bpf_tc_hook_create(&tc_hook); + if (!ASSERT_OK(ret, "bpf_tc_hook_create")) + goto cleanup; + + tc_opts.prog_fd = bpf_program__fd(skel->progs.tc_skb_ext_write_port); + ret = bpf_tc_attach(&tc_hook, &tc_opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) + goto cleanup; + + map = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL, sizeof(int), + sizeof(int), 1, NULL); + if (!ASSERT_GE(map, 0, "bpf_map_create")) + goto cleanup; + + verdict_link = bpf_program__attach_sockmap(skel->progs.sk_skb_skb_ext_read, + map); + if (!ASSERT_OK_PTR(verdict_link, "attach_sockmap")) + goto cleanup; + + if (!ASSERT_OK(create_pair(AF_INET, SOCK_STREAM, &c1, &p1), "create_pair")) + goto cleanup; + + if (!ASSERT_OK(bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST), "map_update")) + goto cleanup; + + if (!ASSERT_OK(getsockname(c1, (struct sockaddr *)&addr, &addr_len), + "getsockname")) + goto cleanup; + skel->bss->target_port = addr.sin_port; + + n = send(p1, test_payload, TEST_PAYLOAD_LEN, 0); + if (!ASSERT_EQ(n, TEST_PAYLOAD_LEN, "send")) + goto cleanup; + + n = recv(c1, buf, sizeof(buf), 0); + ASSERT_EQ(n, TEST_PAYLOAD_LEN, "recv"); + ASSERT_TRUE(skel->bss->test_pass, "test_pass"); + +cleanup: + if (c1 >= 0) + close(c1); + if (p1 >= 0) + close(p1); + bpf_link__destroy(verdict_link); + if (map >= 0) + close(map); + bpf_tc_hook_destroy(&tc_hook); + netns_free(ns); +} + void test_skb_ext_cross_hook(void) { struct test_xdp_meta *skel = NULL; @@ -1591,6 +1668,8 @@ void test_skb_ext_cross_hook(void) skel->progs.lwt_xmit_skb_ext_write, "xmit", true); if (test__start_subtest("tc_to_seg6local")) test_skb_ext_seg6local(skel); + if (test__start_subtest("tc_to_sk_skb")) + test_skb_ext_sk_skb(skel); test_xdp_meta__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_meta.c b/tools/testing/selftests/bpf/progs/test_xdp_meta.c index c4ea38d79533..4c224d5fe1b2 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -1152,4 +1152,22 @@ int seg6local_skb_ext_read(struct __sk_buff *ctx) return BPF_OK; } +/* Read skb_ext from sk_skb stream verdict hook */ +SEC("sk_skb/stream_verdict") +int sk_skb_skb_ext_read(struct __sk_buff *ctx) +{ + __u8 meta_have[META_SIZE]; + struct bpf_dynptr meta; + + if (bpf_dynptr_from_skb_ext(ctx, 0, 0, &meta)) + return SK_PASS; + if (bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0)) + return SK_PASS; + if (!check_metadata(meta_have)) + return SK_PASS; + + test_pass = true; + return SK_PASS; +} + char _license[] SEC("license") = "GPL"; -- 2.43.0