1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <inttypes.h> |
3 | #include <linux/compiler.h> |
4 | #include <linux/kernel.h> |
5 | #include "tests.h" |
6 | #include "map.h" |
7 | #include "maps.h" |
8 | #include "dso.h" |
9 | #include "debug.h" |
10 | |
11 | struct map_def { |
12 | const char *name; |
13 | u64 start; |
14 | u64 end; |
15 | }; |
16 | |
17 | struct check_maps_cb_args { |
18 | struct map_def *merged; |
19 | unsigned int i; |
20 | }; |
21 | |
22 | static int check_maps_cb(struct map *map, void *data) |
23 | { |
24 | struct check_maps_cb_args *args = data; |
25 | struct map_def *merged = &args->merged[args->i]; |
26 | |
27 | if (map__start(map) != merged->start || |
28 | map__end(map) != merged->end || |
29 | strcmp(map__dso(map)->name, merged->name) || |
30 | refcount_read(map__refcnt(map)) != 1) { |
31 | return 1; |
32 | } |
33 | args->i++; |
34 | return 0; |
35 | } |
36 | |
37 | static int failed_cb(struct map *map, void *data __maybe_unused) |
38 | { |
39 | pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n" , |
40 | map__start(map), |
41 | map__end(map), |
42 | map__dso(map)->name, |
43 | refcount_read(map__refcnt(map))); |
44 | |
45 | return 0; |
46 | } |
47 | |
48 | static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps) |
49 | { |
50 | bool failed = false; |
51 | |
52 | if (maps__nr_maps(maps) != size) { |
53 | pr_debug("Expected %d maps, got %d" , size, maps__nr_maps(maps)); |
54 | failed = true; |
55 | } else { |
56 | struct check_maps_cb_args args = { |
57 | .merged = merged, |
58 | .i = 0, |
59 | }; |
60 | failed = maps__for_each_map(maps, check_maps_cb, &args); |
61 | } |
62 | if (failed) { |
63 | pr_debug("Expected:\n" ); |
64 | for (unsigned int i = 0; i < size; i++) { |
65 | pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n" , |
66 | merged[i].start, merged[i].end, merged[i].name); |
67 | } |
68 | pr_debug("Got:\n" ); |
69 | maps__for_each_map(maps, failed_cb, NULL); |
70 | } |
71 | return failed ? TEST_FAIL : TEST_OK; |
72 | } |
73 | |
74 | static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest __maybe_unused) |
75 | { |
76 | unsigned int i; |
77 | struct map_def bpf_progs[] = { |
78 | { "bpf_prog_1" , 200, 300 }, |
79 | { "bpf_prog_2" , 500, 600 }, |
80 | { "bpf_prog_3" , 800, 900 }, |
81 | }; |
82 | struct map_def merged12[] = { |
83 | { "kcore1" , 100, 200 }, |
84 | { "bpf_prog_1" , 200, 300 }, |
85 | { "kcore1" , 300, 500 }, |
86 | { "bpf_prog_2" , 500, 600 }, |
87 | { "kcore1" , 600, 800 }, |
88 | { "bpf_prog_3" , 800, 900 }, |
89 | { "kcore1" , 900, 1000 }, |
90 | }; |
91 | struct map_def merged3[] = { |
92 | { "kcore1" , 100, 200 }, |
93 | { "bpf_prog_1" , 200, 300 }, |
94 | { "kcore1" , 300, 500 }, |
95 | { "bpf_prog_2" , 500, 600 }, |
96 | { "kcore1" , 600, 800 }, |
97 | { "bpf_prog_3" , 800, 900 }, |
98 | { "kcore1" , 900, 1000 }, |
99 | { "kcore3" , 1000, 1100 }, |
100 | }; |
101 | struct map *map_kcore1, *map_kcore2, *map_kcore3; |
102 | int ret; |
103 | struct maps *maps = maps__new(NULL); |
104 | |
105 | TEST_ASSERT_VAL("failed to create maps" , maps); |
106 | |
107 | for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) { |
108 | struct map *map; |
109 | |
110 | map = dso__new_map(bpf_progs[i].name); |
111 | TEST_ASSERT_VAL("failed to create map" , map); |
112 | |
113 | map__set_start(map, bpf_progs[i].start); |
114 | map__set_end(map, bpf_progs[i].end); |
115 | TEST_ASSERT_VAL("failed to insert map" , maps__insert(maps, map) == 0); |
116 | map__put(map); |
117 | } |
118 | |
119 | map_kcore1 = dso__new_map("kcore1" ); |
120 | TEST_ASSERT_VAL("failed to create map" , map_kcore1); |
121 | |
122 | map_kcore2 = dso__new_map("kcore2" ); |
123 | TEST_ASSERT_VAL("failed to create map" , map_kcore2); |
124 | |
125 | map_kcore3 = dso__new_map("kcore3" ); |
126 | TEST_ASSERT_VAL("failed to create map" , map_kcore3); |
127 | |
128 | /* kcore1 map overlaps over all bpf maps */ |
129 | map__set_start(map_kcore1, 100); |
130 | map__set_end(map_kcore1, 1000); |
131 | |
132 | /* kcore2 map hides behind bpf_prog_2 */ |
133 | map__set_start(map_kcore2, 550); |
134 | map__set_end(map_kcore2, 570); |
135 | |
136 | /* kcore3 map hides behind bpf_prog_3, kcore1 and adds new map */ |
137 | map__set_start(map_kcore3, 880); |
138 | map__set_end(map_kcore3, 1100); |
139 | |
140 | ret = maps__merge_in(maps, map_kcore1); |
141 | TEST_ASSERT_VAL("failed to merge map" , !ret); |
142 | |
143 | ret = check_maps(merged: merged12, ARRAY_SIZE(merged12), maps); |
144 | TEST_ASSERT_VAL("merge check failed" , !ret); |
145 | |
146 | ret = maps__merge_in(maps, map_kcore2); |
147 | TEST_ASSERT_VAL("failed to merge map" , !ret); |
148 | |
149 | ret = check_maps(merged: merged12, ARRAY_SIZE(merged12), maps); |
150 | TEST_ASSERT_VAL("merge check failed" , !ret); |
151 | |
152 | ret = maps__merge_in(maps, map_kcore3); |
153 | TEST_ASSERT_VAL("failed to merge map" , !ret); |
154 | |
155 | ret = check_maps(merged: merged3, ARRAY_SIZE(merged3), maps); |
156 | TEST_ASSERT_VAL("merge check failed" , !ret); |
157 | |
158 | maps__zput(maps); |
159 | map__zput(map_kcore1); |
160 | map__zput(map_kcore2); |
161 | map__zput(map_kcore3); |
162 | return TEST_OK; |
163 | } |
164 | |
165 | DEFINE_SUITE("maps__merge_in" , maps__merge_in); |
166 | |