OSDN Git Service

perf/x86/uncore: Correct the number of CHAs on EMR
[tomoyo/tomoyo-test1.git] / tools / testing / selftests / bpf / prog_tests / bpf_obj_pinning.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3 #define _GNU_SOURCE
4 #include <test_progs.h>
5 #include <bpf/btf.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <linux/unistd.h>
9 #include <linux/mount.h>
10 #include <sys/syscall.h>
11
12 static inline int sys_fsopen(const char *fsname, unsigned flags)
13 {
14         return syscall(__NR_fsopen, fsname, flags);
15 }
16
17 static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux)
18 {
19         return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux);
20 }
21
22 static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags)
23 {
24         return syscall(__NR_fsmount, fs_fd, flags, ms_flags);
25 }
26
27 __attribute__((unused))
28 static inline int sys_move_mount(int from_dfd, const char *from_path,
29                                  int to_dfd, const char *to_path,
30                                  unsigned int ms_flags)
31 {
32         return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, ms_flags);
33 }
34
35 static void bpf_obj_pinning_detached(void)
36 {
37         LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts);
38         LIBBPF_OPTS(bpf_obj_get_opts, get_opts);
39         int fs_fd = -1, mnt_fd = -1;
40         int map_fd = -1, map_fd2 = -1;
41         int zero = 0, src_value, dst_value, err;
42         const char *map_name = "fsmount_map";
43
44         /* A bunch of below UAPI calls are constructed based on reading:
45          * https://brauner.io/2023/02/28/mounting-into-mount-namespaces.html
46          */
47
48         /* create VFS context */
49         fs_fd = sys_fsopen("bpf", 0);
50         if (!ASSERT_GE(fs_fd, 0, "fs_fd"))
51                 goto cleanup;
52
53         /* instantiate FS object */
54         err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
55         if (!ASSERT_OK(err, "fs_create"))
56                 goto cleanup;
57
58         /* create O_PATH fd for detached mount */
59         mnt_fd = sys_fsmount(fs_fd, 0, 0);
60         if (!ASSERT_GE(mnt_fd, 0, "mnt_fd"))
61                 goto cleanup;
62
63         /* If we wanted to expose detached mount in the file system, we'd do
64          * something like below. But the whole point is that we actually don't
65          * even have to expose BPF FS in the file system to be able to work
66          * (pin/get objects) with it.
67          *
68          * err = sys_move_mount(mnt_fd, "", -EBADF, mnt_path, MOVE_MOUNT_F_EMPTY_PATH);
69          * if (!ASSERT_OK(err, "move_mount"))
70          *      goto cleanup;
71          */
72
73         /* create BPF map to pin */
74         map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL);
75         if (!ASSERT_GE(map_fd, 0, "map_fd"))
76                 goto cleanup;
77
78         /* pin BPF map into detached BPF FS through mnt_fd */
79         pin_opts.file_flags = BPF_F_PATH_FD;
80         pin_opts.path_fd = mnt_fd;
81         err = bpf_obj_pin_opts(map_fd, map_name, &pin_opts);
82         if (!ASSERT_OK(err, "map_pin"))
83                 goto cleanup;
84
85         /* get BPF map from detached BPF FS through mnt_fd */
86         get_opts.file_flags = BPF_F_PATH_FD;
87         get_opts.path_fd = mnt_fd;
88         map_fd2 = bpf_obj_get_opts(map_name, &get_opts);
89         if (!ASSERT_GE(map_fd2, 0, "map_get"))
90                 goto cleanup;
91
92         /* update map through one FD */
93         src_value = 0xcafebeef;
94         err = bpf_map_update_elem(map_fd, &zero, &src_value, 0);
95         ASSERT_OK(err, "map_update");
96
97         /* check values written/read through different FDs do match */
98         dst_value = 0;
99         err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value);
100         ASSERT_OK(err, "map_lookup");
101         ASSERT_EQ(dst_value, src_value, "map_value_eq1");
102         ASSERT_EQ(dst_value, 0xcafebeef, "map_value_eq2");
103
104 cleanup:
105         if (map_fd >= 0)
106                 ASSERT_OK(close(map_fd), "close_map_fd");
107         if (map_fd2 >= 0)
108                 ASSERT_OK(close(map_fd2), "close_map_fd2");
109         if (fs_fd >= 0)
110                 ASSERT_OK(close(fs_fd), "close_fs_fd");
111         if (mnt_fd >= 0)
112                 ASSERT_OK(close(mnt_fd), "close_mnt_fd");
113 }
114
115 enum path_kind
116 {
117         PATH_STR_ABS,
118         PATH_STR_REL,
119         PATH_FD_REL,
120 };
121
122 static void validate_pin(int map_fd, const char *map_name, int src_value,
123                          enum path_kind path_kind)
124 {
125         LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts);
126         char abs_path[PATH_MAX], old_cwd[PATH_MAX];
127         const char *pin_path = NULL;
128         int zero = 0, dst_value, map_fd2, err;
129
130         snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name);
131         old_cwd[0] = '\0';
132
133         switch (path_kind) {
134         case PATH_STR_ABS:
135                 /* absolute path */
136                 pin_path = abs_path;
137                 break;
138         case PATH_STR_REL:
139                 /* cwd + relative path */
140                 ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd");
141                 ASSERT_OK(chdir("/sys/fs/bpf"), "chdir");
142                 pin_path = map_name;
143                 break;
144         case PATH_FD_REL:
145                 /* dir fd + relative path */
146                 pin_opts.file_flags = BPF_F_PATH_FD;
147                 pin_opts.path_fd = open("/sys/fs/bpf", O_PATH);
148                 ASSERT_GE(pin_opts.path_fd, 0, "path_fd");
149                 pin_path = map_name;
150                 break;
151         }
152
153         /* pin BPF map using specified path definition */
154         err = bpf_obj_pin_opts(map_fd, pin_path, &pin_opts);
155         ASSERT_OK(err, "obj_pin");
156
157         /* cleanup */
158         if (pin_opts.path_fd >= 0)
159                 close(pin_opts.path_fd);
160         if (old_cwd[0])
161                 ASSERT_OK(chdir(old_cwd), "restore_cwd");
162
163         map_fd2 = bpf_obj_get(abs_path);
164         if (!ASSERT_GE(map_fd2, 0, "map_get"))
165                 goto cleanup;
166
167         /* update map through one FD */
168         err = bpf_map_update_elem(map_fd, &zero, &src_value, 0);
169         ASSERT_OK(err, "map_update");
170
171         /* check values written/read through different FDs do match */
172         dst_value = 0;
173         err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value);
174         ASSERT_OK(err, "map_lookup");
175         ASSERT_EQ(dst_value, src_value, "map_value_eq");
176 cleanup:
177         if (map_fd2 >= 0)
178                 ASSERT_OK(close(map_fd2), "close_map_fd2");
179         unlink(abs_path);
180 }
181
182 static void validate_get(int map_fd, const char *map_name, int src_value,
183                          enum path_kind path_kind)
184 {
185         LIBBPF_OPTS(bpf_obj_get_opts, get_opts);
186         char abs_path[PATH_MAX], old_cwd[PATH_MAX];
187         const char *pin_path = NULL;
188         int zero = 0, dst_value, map_fd2, err;
189
190         snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name);
191         /* pin BPF map using specified path definition */
192         err = bpf_obj_pin(map_fd, abs_path);
193         if (!ASSERT_OK(err, "pin_map"))
194                 return;
195
196         old_cwd[0] = '\0';
197
198         switch (path_kind) {
199         case PATH_STR_ABS:
200                 /* absolute path */
201                 pin_path = abs_path;
202                 break;
203         case PATH_STR_REL:
204                 /* cwd + relative path */
205                 ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd");
206                 ASSERT_OK(chdir("/sys/fs/bpf"), "chdir");
207                 pin_path = map_name;
208                 break;
209         case PATH_FD_REL:
210                 /* dir fd + relative path */
211                 get_opts.file_flags = BPF_F_PATH_FD;
212                 get_opts.path_fd = open("/sys/fs/bpf", O_PATH);
213                 ASSERT_GE(get_opts.path_fd, 0, "path_fd");
214                 pin_path = map_name;
215                 break;
216         }
217
218         map_fd2 = bpf_obj_get_opts(pin_path, &get_opts);
219         if (!ASSERT_GE(map_fd2, 0, "map_get"))
220                 goto cleanup;
221
222         /* cleanup */
223         if (get_opts.path_fd >= 0)
224                 close(get_opts.path_fd);
225         if (old_cwd[0])
226                 ASSERT_OK(chdir(old_cwd), "restore_cwd");
227
228         /* update map through one FD */
229         err = bpf_map_update_elem(map_fd, &zero, &src_value, 0);
230         ASSERT_OK(err, "map_update");
231
232         /* check values written/read through different FDs do match */
233         dst_value = 0;
234         err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value);
235         ASSERT_OK(err, "map_lookup");
236         ASSERT_EQ(dst_value, src_value, "map_value_eq");
237 cleanup:
238         if (map_fd2 >= 0)
239                 ASSERT_OK(close(map_fd2), "close_map_fd2");
240         unlink(abs_path);
241 }
242
243 static void bpf_obj_pinning_mounted(enum path_kind path_kind)
244 {
245         const char *map_name = "mounted_map";
246         int map_fd;
247
248         /* create BPF map to pin */
249         map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL);
250         if (!ASSERT_GE(map_fd, 0, "map_fd"))
251                 return;
252
253         validate_pin(map_fd, map_name, 100 + (int)path_kind, path_kind);
254         validate_get(map_fd, map_name, 200 + (int)path_kind, path_kind);
255         ASSERT_OK(close(map_fd), "close_map_fd");
256 }
257
258 void test_bpf_obj_pinning()
259 {
260         if (test__start_subtest("detached"))
261                 bpf_obj_pinning_detached();
262         if (test__start_subtest("mounted-str-abs"))
263                 bpf_obj_pinning_mounted(PATH_STR_ABS);
264         if (test__start_subtest("mounted-str-rel"))
265                 bpf_obj_pinning_mounted(PATH_STR_REL);
266         if (test__start_subtest("mounted-fd-rel"))
267                 bpf_obj_pinning_mounted(PATH_FD_REL);
268 }