[PATCH net-next 07/14] selftests/bpf: Test skb_ext read from cgroup_skb and sk_filter hooks
Jakub Sitnicki <[email protected]>
| Newsgroups | org.kernel.vger.bpf,org.kernel.vger.netdev |
|---|---|
| Message-ID | <20260814-bpf-meta-inside-skb-ext-v1-7-767edd862656@cloudflare.com> |
Extend skb_ext cross-hook coverage to UDP readers: attach a TC ingress program on loopback that writes the extension, send a UDP datagram over loopback, and read the extension back from a cgroup_skb/ingress program and from a socket filter attached with SO_ATTACH_BPF. Signed-off-by: Jakub Sitnicki <[email protected]> --- .../bpf/prog_tests/xdp_context_test_run.c | 121 +++++++++++++++++++++ tools/testing/selftests/bpf/progs/test_xdp_meta.c | 37 +++++++ 2 files changed, 158 insertions(+) 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 de6030302536..808eb158fe0f 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 @@ -992,3 +992,124 @@ void test_skb_ext_basic(void) test_xdp_meta__destroy(skel); } + +/* Send test_payload over loopback UDP to recv_fd */ +static int send_loopback_udp(int recv_fd) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + char buf[TEST_PAYLOAD_LEN]; + int ret = -1; + int fd = -1; + __be16 port; + + port = get_socket_local_port(recv_fd); + if (!ASSERT_GE(port, 0, "get_port")) + goto out; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (!ASSERT_GE(fd, 0, "socket")) + goto out; + + addr.sin_port = port; + sendto(fd, test_payload, TEST_PAYLOAD_LEN, 0, + (void *)&addr, sizeof(addr)); + recvfrom(recv_fd, buf, sizeof(buf), 0, NULL, NULL); + ret = 0; +out: + if (fd >= 0) + close(fd); + return ret; +} + +enum udp_reader_type { + READER_CGRP_SKB, + READER_SK_FILTER, +}; + +/* Test skb_ext survival across TC ingress -> UDP reader hook */ +static void test_skb_ext_udp(struct test_xdp_meta *skel, const char *name, + enum udp_reader_type reader) +{ + 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 *reader_link = NULL; + struct netns_obj *ns = NULL; + int server_fd = -1; + int cgroup_fd = -1; + int filter_fd; + int ret; + + ns = netns_new(name, true); + if (!ASSERT_OK_PTR(ns, "netns_new")) + return; + + cgroup_fd = test__join_cgroup(name); + if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup")) + goto cleanup; + + server_fd = start_server(AF_INET, SOCK_DGRAM, "127.0.0.1", 0, 0); + if (!ASSERT_GE(server_fd, 0, "start_server")) + goto cleanup; + + 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); + ret = bpf_tc_attach(&tc_hook, &tc_opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) + goto cleanup; + + switch (reader) { + case READER_CGRP_SKB: + reader_link = bpf_program__attach_cgroup(skel->progs.cgrp_skb_ext_read, + cgroup_fd); + if (!ASSERT_OK_PTR(reader_link, "attach_cgroup")) + goto cleanup; + break; + case READER_SK_FILTER: + filter_fd = bpf_program__fd(skel->progs.sk_filter_skb_ext_read); + ret = setsockopt(server_fd, SOL_SOCKET, SO_ATTACH_BPF, + &filter_fd, sizeof(filter_fd)); + if (!ASSERT_OK(ret, "attach_socket_filter")) + goto cleanup; + break; + } + + if (send_loopback_udp(server_fd)) + goto cleanup; + + ASSERT_TRUE(skel->bss->test_pass, "test_pass"); + +cleanup: + bpf_link__destroy(reader_link); + bpf_tc_hook_destroy(&tc_hook); + if (server_fd >= 0) + close(server_fd); + if (cgroup_fd >= 0) + close(cgroup_fd); + netns_free(ns); +} + +void test_skb_ext_cross_hook(void) +{ + struct test_xdp_meta *skel = NULL; + + skel = test_xdp_meta__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open and load skeleton")) + return; + + if (test__start_subtest("tc_to_cgrp_ingress")) + test_skb_ext_udp(skel, "tc_to_cgrp_ingress", READER_CGRP_SKB); + if (test__start_subtest("tc_to_sk_filter")) + test_skb_ext_udp(skel, "tc_to_sk_filter", READER_SK_FILTER); + + 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 1b6bb20ee7e8..0a3afb5c3461 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_meta.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_meta.c @@ -920,4 +920,41 @@ int BPF_PROG(tp_kfree_skb_cow_check, struct sk_buff *skb) return 0; } +/* Read skb_ext from cgroup/skb ingress -- tests cross-hook survival */ +SEC("cgroup_skb/ingress") +int cgrp_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 1; + if (bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0)) + return 1; + if (!check_metadata(meta_have)) + return 1; + + test_pass = true; + return 1; +} + +/* Read skb_ext from socket filter -- tests TC -> sk_filter path */ +SEC("socket") +int sk_filter_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)) + goto out; + if (bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0)) + goto out; + if (!check_metadata(meta_have)) + goto out; + + test_pass = true; +out: + return ctx->len; +} + char _license[] SEC("license") = "GPL"; -- 2.43.0