Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020 Facebook */
0003 
0004 #include <test_progs.h>
0005 
0006 #include "test_btf_map_in_map.skel.h"
0007 
0008 static int duration;
0009 
0010 static __u32 bpf_map_id(struct bpf_map *map)
0011 {
0012     struct bpf_map_info info;
0013     __u32 info_len = sizeof(info);
0014     int err;
0015 
0016     memset(&info, 0, info_len);
0017     err = bpf_obj_get_info_by_fd(bpf_map__fd(map), &info, &info_len);
0018     if (err)
0019         return 0;
0020     return info.id;
0021 }
0022 
0023 static void test_lookup_update(void)
0024 {
0025     int map1_fd, map2_fd, map3_fd, map4_fd, map5_fd, map1_id, map2_id;
0026     int outer_arr_fd, outer_hash_fd, outer_arr_dyn_fd;
0027     struct test_btf_map_in_map *skel;
0028     int err, key = 0, val, i, fd;
0029 
0030     skel = test_btf_map_in_map__open_and_load();
0031     if (CHECK(!skel, "skel_open", "failed to open&load skeleton\n"))
0032         return;
0033 
0034     err = test_btf_map_in_map__attach(skel);
0035     if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
0036         goto cleanup;
0037 
0038     map1_fd = bpf_map__fd(skel->maps.inner_map1);
0039     map2_fd = bpf_map__fd(skel->maps.inner_map2);
0040     map3_fd = bpf_map__fd(skel->maps.inner_map3);
0041     map4_fd = bpf_map__fd(skel->maps.inner_map4);
0042     map5_fd = bpf_map__fd(skel->maps.inner_map5);
0043     outer_arr_dyn_fd = bpf_map__fd(skel->maps.outer_arr_dyn);
0044     outer_arr_fd = bpf_map__fd(skel->maps.outer_arr);
0045     outer_hash_fd = bpf_map__fd(skel->maps.outer_hash);
0046 
0047     /* inner1 = input, inner2 = input + 1, inner3 = input + 2 */
0048     bpf_map_update_elem(outer_arr_fd, &key, &map1_fd, 0);
0049     bpf_map_update_elem(outer_hash_fd, &key, &map2_fd, 0);
0050     bpf_map_update_elem(outer_arr_dyn_fd, &key, &map3_fd, 0);
0051     skel->bss->input = 1;
0052     usleep(1);
0053     bpf_map_lookup_elem(map1_fd, &key, &val);
0054     CHECK(val != 1, "inner1", "got %d != exp %d\n", val, 1);
0055     bpf_map_lookup_elem(map2_fd, &key, &val);
0056     CHECK(val != 2, "inner2", "got %d != exp %d\n", val, 2);
0057     bpf_map_lookup_elem(map3_fd, &key, &val);
0058     CHECK(val != 3, "inner3", "got %d != exp %d\n", val, 3);
0059 
0060     /* inner2 = input, inner1 = input + 1, inner4 = input + 2 */
0061     bpf_map_update_elem(outer_arr_fd, &key, &map2_fd, 0);
0062     bpf_map_update_elem(outer_hash_fd, &key, &map1_fd, 0);
0063     bpf_map_update_elem(outer_arr_dyn_fd, &key, &map4_fd, 0);
0064     skel->bss->input = 3;
0065     usleep(1);
0066     bpf_map_lookup_elem(map1_fd, &key, &val);
0067     CHECK(val != 4, "inner1", "got %d != exp %d\n", val, 4);
0068     bpf_map_lookup_elem(map2_fd, &key, &val);
0069     CHECK(val != 3, "inner2", "got %d != exp %d\n", val, 3);
0070     bpf_map_lookup_elem(map4_fd, &key, &val);
0071     CHECK(val != 5, "inner4", "got %d != exp %d\n", val, 5);
0072 
0073     /* inner5 = input + 2 */
0074     bpf_map_update_elem(outer_arr_dyn_fd, &key, &map5_fd, 0);
0075     skel->bss->input = 5;
0076     usleep(1);
0077     bpf_map_lookup_elem(map5_fd, &key, &val);
0078     CHECK(val != 7, "inner5", "got %d != exp %d\n", val, 7);
0079 
0080     for (i = 0; i < 5; i++) {
0081         val = i % 2 ? map1_fd : map2_fd;
0082         err = bpf_map_update_elem(outer_hash_fd, &key, &val, 0);
0083         if (CHECK_FAIL(err)) {
0084             printf("failed to update hash_of_maps on iter #%d\n", i);
0085             goto cleanup;
0086         }
0087         err = bpf_map_update_elem(outer_arr_fd, &key, &val, 0);
0088         if (CHECK_FAIL(err)) {
0089             printf("failed to update array_of_maps on iter #%d\n", i);
0090             goto cleanup;
0091         }
0092         val = i % 2 ? map4_fd : map5_fd;
0093         err = bpf_map_update_elem(outer_arr_dyn_fd, &key, &val, 0);
0094         if (CHECK_FAIL(err)) {
0095             printf("failed to update array_of_maps (dyn) on iter #%d\n", i);
0096             goto cleanup;
0097         }
0098     }
0099 
0100     map1_id = bpf_map_id(skel->maps.inner_map1);
0101     map2_id = bpf_map_id(skel->maps.inner_map2);
0102     CHECK(map1_id == 0, "map1_id", "failed to get ID 1\n");
0103     CHECK(map2_id == 0, "map2_id", "failed to get ID 2\n");
0104 
0105     test_btf_map_in_map__destroy(skel);
0106     skel = NULL;
0107 
0108     /* we need to either wait for or force synchronize_rcu(), before
0109      * checking for "still exists" condition, otherwise map could still be
0110      * resolvable by ID, causing false positives.
0111      *
0112      * Older kernels (5.8 and earlier) freed map only after two
0113      * synchronize_rcu()s, so trigger two, to be entirely sure.
0114      */
0115     CHECK(kern_sync_rcu(), "sync_rcu", "failed\n");
0116     CHECK(kern_sync_rcu(), "sync_rcu", "failed\n");
0117 
0118     fd = bpf_map_get_fd_by_id(map1_id);
0119     if (CHECK(fd >= 0, "map1_leak", "inner_map1 leaked!\n")) {
0120         close(fd);
0121         goto cleanup;
0122     }
0123     fd = bpf_map_get_fd_by_id(map2_id);
0124     if (CHECK(fd >= 0, "map2_leak", "inner_map2 leaked!\n")) {
0125         close(fd);
0126         goto cleanup;
0127     }
0128 
0129 cleanup:
0130     test_btf_map_in_map__destroy(skel);
0131 }
0132 
0133 static void test_diff_size(void)
0134 {
0135     struct test_btf_map_in_map *skel;
0136     int err, inner_map_fd, zero = 0;
0137 
0138     skel = test_btf_map_in_map__open_and_load();
0139     if (CHECK(!skel, "skel_open", "failed to open&load skeleton\n"))
0140         return;
0141 
0142     inner_map_fd = bpf_map__fd(skel->maps.sockarr_sz2);
0143     err = bpf_map_update_elem(bpf_map__fd(skel->maps.outer_sockarr), &zero,
0144                   &inner_map_fd, 0);
0145     CHECK(err, "outer_sockarr inner map size check",
0146           "cannot use a different size inner_map\n");
0147 
0148     inner_map_fd = bpf_map__fd(skel->maps.inner_map_sz2);
0149     err = bpf_map_update_elem(bpf_map__fd(skel->maps.outer_arr), &zero,
0150                   &inner_map_fd, 0);
0151     CHECK(!err, "outer_arr inner map size check",
0152           "incorrectly updated with a different size inner_map\n");
0153 
0154     test_btf_map_in_map__destroy(skel);
0155 }
0156 
0157 void test_btf_map_in_map(void)
0158 {
0159     if (test__start_subtest("lookup_update"))
0160         test_lookup_update();
0161 
0162     if (test__start_subtest("diff_size"))
0163         test_diff_size();
0164 }