124999636SMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0 224999636SMykyta Yatsenko /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 324999636SMykyta Yatsenko #include <test_progs.h> 424999636SMykyta Yatsenko #include <string.h> 524999636SMykyta Yatsenko #include <stdio.h> 624999636SMykyta Yatsenko #include "rhash.skel.h" 7*a996794fSMykyta Yatsenko #include "bpf_iter_bpf_rhash_map.skel.h" 824999636SMykyta Yatsenko #include <linux/bpf.h> 924999636SMykyta Yatsenko #include <linux/perf_event.h> 1024999636SMykyta Yatsenko #include <sys/syscall.h> 1124999636SMykyta Yatsenko 1224999636SMykyta Yatsenko static void rhash_run(const char *prog_name) 1324999636SMykyta Yatsenko { 1424999636SMykyta Yatsenko struct rhash *skel; 1524999636SMykyta Yatsenko struct bpf_program *prog; 1624999636SMykyta Yatsenko LIBBPF_OPTS(bpf_test_run_opts, opts); 1724999636SMykyta Yatsenko int err; 1824999636SMykyta Yatsenko 1924999636SMykyta Yatsenko skel = rhash__open(); 2024999636SMykyta Yatsenko if (!ASSERT_OK_PTR(skel, "rhash__open")) 2124999636SMykyta Yatsenko return; 2224999636SMykyta Yatsenko 2324999636SMykyta Yatsenko prog = bpf_object__find_program_by_name(skel->obj, prog_name); 2424999636SMykyta Yatsenko if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) 2524999636SMykyta Yatsenko goto cleanup; 2624999636SMykyta Yatsenko bpf_program__set_autoload(prog, true); 2724999636SMykyta Yatsenko 2824999636SMykyta Yatsenko err = rhash__load(skel); 2924999636SMykyta Yatsenko if (!ASSERT_OK(err, "skel_load")) 3024999636SMykyta Yatsenko goto cleanup; 3124999636SMykyta Yatsenko 3224999636SMykyta Yatsenko err = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts); 3324999636SMykyta Yatsenko if (!ASSERT_OK(err, "prog run")) 3424999636SMykyta Yatsenko goto cleanup; 3524999636SMykyta Yatsenko 3624999636SMykyta Yatsenko if (!ASSERT_OK(opts.retval, "prog retval")) 3724999636SMykyta Yatsenko goto cleanup; 3824999636SMykyta Yatsenko 3924999636SMykyta Yatsenko if (!ASSERT_OK(skel->bss->err, "bss->err")) 4024999636SMykyta Yatsenko goto cleanup; 4124999636SMykyta Yatsenko 4224999636SMykyta Yatsenko cleanup: 4324999636SMykyta Yatsenko rhash__destroy(skel); 4424999636SMykyta Yatsenko } 4524999636SMykyta Yatsenko 4624999636SMykyta Yatsenko static int rhash_map_create(__u32 max_entries, __u64 map_extra) 4724999636SMykyta Yatsenko { 4824999636SMykyta Yatsenko LIBBPF_OPTS(bpf_map_create_opts, opts, 4924999636SMykyta Yatsenko .map_flags = BPF_F_NO_PREALLOC, 5024999636SMykyta Yatsenko .map_extra = map_extra); 5124999636SMykyta Yatsenko 5224999636SMykyta Yatsenko return bpf_map_create(BPF_MAP_TYPE_RHASH, "rhash_extra", 5324999636SMykyta Yatsenko sizeof(__u32), sizeof(__u64), max_entries, &opts); 5424999636SMykyta Yatsenko } 5524999636SMykyta Yatsenko 5624999636SMykyta Yatsenko static void rhash_map_extra_presize(void) 5724999636SMykyta Yatsenko { 5824999636SMykyta Yatsenko const __u32 max_entries = 1024; 5924999636SMykyta Yatsenko const __u32 nelem_hint = 256; 6024999636SMykyta Yatsenko struct bpf_map_info info = {}; 6124999636SMykyta Yatsenko __u32 info_len = sizeof(info); 6224999636SMykyta Yatsenko __u64 val = 0; 6324999636SMykyta Yatsenko __u32 key; 6424999636SMykyta Yatsenko int fd, i; 6524999636SMykyta Yatsenko 6624999636SMykyta Yatsenko fd = rhash_map_create(max_entries, nelem_hint); 6724999636SMykyta Yatsenko if (!ASSERT_GE(fd, 0, "rhash_map_create presize")) 6824999636SMykyta Yatsenko return; 6924999636SMykyta Yatsenko 7024999636SMykyta Yatsenko if (!ASSERT_OK(bpf_map_get_info_by_fd(fd, &info, &info_len), "info")) 7124999636SMykyta Yatsenko goto close; 7224999636SMykyta Yatsenko ASSERT_EQ(info.map_extra, nelem_hint, "info.map_extra"); 7324999636SMykyta Yatsenko 7424999636SMykyta Yatsenko for (i = 0; i < (int)nelem_hint; i++) { 7524999636SMykyta Yatsenko key = i; 7624999636SMykyta Yatsenko if (!ASSERT_OK(bpf_map_update_elem(fd, &key, &val, BPF_NOEXIST), 7724999636SMykyta Yatsenko "update")) 7824999636SMykyta Yatsenko goto close; 7924999636SMykyta Yatsenko } 8024999636SMykyta Yatsenko close: 8124999636SMykyta Yatsenko close(fd); 8224999636SMykyta Yatsenko } 8324999636SMykyta Yatsenko 8424999636SMykyta Yatsenko static void rhash_map_extra_too_big(void) 8524999636SMykyta Yatsenko { 8624999636SMykyta Yatsenko int fd; 8724999636SMykyta Yatsenko 8824999636SMykyta Yatsenko fd = rhash_map_create(1U << 20, 0x10000); 8924999636SMykyta Yatsenko if (!ASSERT_LT(fd, 0, "rhash_map_create hint > U16_MAX")) 9024999636SMykyta Yatsenko close(fd); 9124999636SMykyta Yatsenko } 9224999636SMykyta Yatsenko 93*a996794fSMykyta Yatsenko static void rhash_iter_test(void) 94*a996794fSMykyta Yatsenko { 95*a996794fSMykyta Yatsenko DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); 96*a996794fSMykyta Yatsenko struct bpf_iter_bpf_rhash_map *skel; 97*a996794fSMykyta Yatsenko int err, i, len, map_fd, iter_fd; 98*a996794fSMykyta Yatsenko union bpf_iter_link_info linfo; 99*a996794fSMykyta Yatsenko u32 expected_key_sum = 0, key; 100*a996794fSMykyta Yatsenko struct bpf_link *link; 101*a996794fSMykyta Yatsenko u64 val = 0; 102*a996794fSMykyta Yatsenko char buf[64]; 103*a996794fSMykyta Yatsenko 104*a996794fSMykyta Yatsenko skel = bpf_iter_bpf_rhash_map__open(); 105*a996794fSMykyta Yatsenko if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_rhash_map__open")) 106*a996794fSMykyta Yatsenko return; 107*a996794fSMykyta Yatsenko 108*a996794fSMykyta Yatsenko err = bpf_iter_bpf_rhash_map__load(skel); 109*a996794fSMykyta Yatsenko if (!ASSERT_OK(err, "bpf_iter_bpf_rhash_map__load")) 110*a996794fSMykyta Yatsenko goto out; 111*a996794fSMykyta Yatsenko 112*a996794fSMykyta Yatsenko map_fd = bpf_map__fd(skel->maps.rhashmap); 113*a996794fSMykyta Yatsenko 114*a996794fSMykyta Yatsenko /* Populate map with test data */ 115*a996794fSMykyta Yatsenko for (i = 0; i < 64; i++) { 116*a996794fSMykyta Yatsenko key = i + 1; 117*a996794fSMykyta Yatsenko expected_key_sum += key; 118*a996794fSMykyta Yatsenko 119*a996794fSMykyta Yatsenko err = bpf_map_update_elem(map_fd, &key, &val, BPF_NOEXIST); 120*a996794fSMykyta Yatsenko if (!ASSERT_OK(err, "map_update")) 121*a996794fSMykyta Yatsenko goto out; 122*a996794fSMykyta Yatsenko } 123*a996794fSMykyta Yatsenko 124*a996794fSMykyta Yatsenko memset(&linfo, 0, sizeof(linfo)); 125*a996794fSMykyta Yatsenko linfo.map.map_fd = map_fd; 126*a996794fSMykyta Yatsenko opts.link_info = &linfo; 127*a996794fSMykyta Yatsenko opts.link_info_len = sizeof(linfo); 128*a996794fSMykyta Yatsenko 129*a996794fSMykyta Yatsenko link = bpf_program__attach_iter(skel->progs.dump_bpf_rhash_map, &opts); 130*a996794fSMykyta Yatsenko if (!ASSERT_OK_PTR(link, "attach_iter")) 131*a996794fSMykyta Yatsenko goto out; 132*a996794fSMykyta Yatsenko 133*a996794fSMykyta Yatsenko iter_fd = bpf_iter_create(bpf_link__fd(link)); 134*a996794fSMykyta Yatsenko if (!ASSERT_GE(iter_fd, 0, "create_iter")) 135*a996794fSMykyta Yatsenko goto free_link; 136*a996794fSMykyta Yatsenko 137*a996794fSMykyta Yatsenko do { 138*a996794fSMykyta Yatsenko len = read(iter_fd, buf, sizeof(buf)); 139*a996794fSMykyta Yatsenko } while (len > 0); 140*a996794fSMykyta Yatsenko 141*a996794fSMykyta Yatsenko ASSERT_EQ(skel->bss->key_sum, expected_key_sum, "key_sum"); 142*a996794fSMykyta Yatsenko ASSERT_EQ(skel->bss->elem_count, 64, "elem_count"); 143*a996794fSMykyta Yatsenko 144*a996794fSMykyta Yatsenko close(iter_fd); 145*a996794fSMykyta Yatsenko 146*a996794fSMykyta Yatsenko free_link: 147*a996794fSMykyta Yatsenko bpf_link__destroy(link); 148*a996794fSMykyta Yatsenko out: 149*a996794fSMykyta Yatsenko bpf_iter_bpf_rhash_map__destroy(skel); 150*a996794fSMykyta Yatsenko } 151*a996794fSMykyta Yatsenko 15224999636SMykyta Yatsenko void test_rhash(void) 15324999636SMykyta Yatsenko { 15424999636SMykyta Yatsenko if (test__start_subtest("test_rhash_lookup_update")) 15524999636SMykyta Yatsenko rhash_run("test_rhash_lookup_update"); 15624999636SMykyta Yatsenko 15724999636SMykyta Yatsenko if (test__start_subtest("test_rhash_update_delete")) 15824999636SMykyta Yatsenko rhash_run("test_rhash_update_delete"); 15924999636SMykyta Yatsenko 16024999636SMykyta Yatsenko if (test__start_subtest("test_rhash_update_elements")) 16124999636SMykyta Yatsenko rhash_run("test_rhash_update_elements"); 16224999636SMykyta Yatsenko 16324999636SMykyta Yatsenko if (test__start_subtest("test_rhash_update_exist")) 16424999636SMykyta Yatsenko rhash_run("test_rhash_update_exist"); 16524999636SMykyta Yatsenko 16624999636SMykyta Yatsenko if (test__start_subtest("test_rhash_update_any")) 16724999636SMykyta Yatsenko rhash_run("test_rhash_update_any"); 16824999636SMykyta Yatsenko 16924999636SMykyta Yatsenko if (test__start_subtest("test_rhash_noexist_duplicate")) 17024999636SMykyta Yatsenko rhash_run("test_rhash_noexist_duplicate"); 17124999636SMykyta Yatsenko 17224999636SMykyta Yatsenko if (test__start_subtest("test_rhash_delete_nonexistent")) 17324999636SMykyta Yatsenko rhash_run("test_rhash_delete_nonexistent"); 17424999636SMykyta Yatsenko 17524999636SMykyta Yatsenko if (test__start_subtest("test_rhash_map_extra_presize")) 17624999636SMykyta Yatsenko rhash_map_extra_presize(); 17724999636SMykyta Yatsenko 17824999636SMykyta Yatsenko if (test__start_subtest("test_rhash_map_extra_too_big")) 17924999636SMykyta Yatsenko rhash_map_extra_too_big(); 180*a996794fSMykyta Yatsenko 181*a996794fSMykyta Yatsenko if (test__start_subtest("test_rhash_iter")) 182*a996794fSMykyta Yatsenko rhash_iter_test(); 18324999636SMykyta Yatsenko } 184