]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bpf-dlopen.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / shared / bpf-dlopen.c
CommitLineData
c5fd89ad
LB
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
c5fd89ad 3#include "bpf-dlopen.h"
1cf40697 4#include "dlfcn-util.h"
1622ef77 5#include "log.h"
c5fd89ad
LB
6
7#if HAVE_LIBBPF
7736a71f
LP
8
9/* libbpf changed types of function prototypes around, so we need to disable some type checking for older
10 * libbpf. We consider everything older than 0.7 too old for accurate type checks. */
11#if defined(__LIBBPF_CURRENT_VERSION_GEQ)
12#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7)
13#define MODERN_LIBBPF 1
14#endif
15#endif
16#if !defined(MODERN_LIBBPF)
17#define MODERN_LIBBPF 0
18#endif
19
5c672e90
ZJS
20DLSYM_PROTOTYPE(bpf_link__destroy) = NULL;
21DLSYM_PROTOTYPE(bpf_link__fd) = NULL;
22DLSYM_PROTOTYPE(bpf_link__open) = NULL;
23DLSYM_PROTOTYPE(bpf_link__pin) = NULL;
24DLSYM_PROTOTYPE(bpf_map__fd) = NULL;
25DLSYM_PROTOTYPE(bpf_map__name) = NULL;
26DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL;
27DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL;
28DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL;
29DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL;
30DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL;
31DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL;
32DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL;
33DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL;
34DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL;
35DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL;
36DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL;
37DLSYM_PROTOTYPE(bpf_object__name) = NULL;
38DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL;
39DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL;
40DLSYM_PROTOTYPE(bpf_program__attach) = NULL;
41DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL;
42DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL;
43DLSYM_PROTOTYPE(bpf_program__name) = NULL;
44DLSYM_PROTOTYPE(libbpf_get_error) = NULL;
45DLSYM_PROTOTYPE(libbpf_set_print) = NULL;
46DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL;
47DLSYM_PROTOTYPE(ring_buffer__free) = NULL;
48DLSYM_PROTOTYPE(ring_buffer__new) = NULL;
49DLSYM_PROTOTYPE(ring_buffer__poll) = NULL;
9dbabd0a
LP
50
51/* new symbols available from libbpf 0.7.0 */
6b8085db 52int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *);
0f716ace 53struct bpf_map* (*sym_bpf_object__next_map)(const struct bpf_object *obj, const struct bpf_map *map);
44005a57 54
87e462f7
DM
55/* compat symbols removed in libbpf 1.0 */
56int (*sym_bpf_create_map)(enum bpf_map_type, int key_size, int value_size, int max_entries, __u32 map_flags);
87e462f7 57
44005a57
ZJS
58_printf_(2,0)
59static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) {
60#if !LOG_TRACE
61 /* libbpf logs a lot of details at its debug level, which we don't need to see. */
62 if (level == LIBBPF_DEBUG)
63 return 0;
64#endif
65 /* All other levels are downgraded to LOG_DEBUG */
66
67 /* errno is used here, on the assumption that if the log message uses %m, errno will be set to
68 * something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */
69 return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap);
70}
c5fd89ad 71
4d2b9abb
YW
72int dlopen_bpf_full(int log_level) {
73 static int cached = 0;
87e462f7 74 void *dl;
44005a57
ZJS
75 int r;
76
4d2b9abb
YW
77 if (cached != 0)
78 return cached;
79
cd7c2077
LP
80 ELF_NOTE_DLOPEN("bpf",
81 "Support firewalling and sandboxing with BPF",
82 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
83 "libbpf.so.1", "libbpf.so.0");
84
7736a71f
LP
85 DISABLE_WARNING_DEPRECATED_DECLARATIONS;
86
bd4beaa2 87 dl = dlopen("libbpf.so.1", RTLD_NOW|RTLD_NODELETE);
87e462f7
DM
88 if (!dl) {
89 /* libbpf < 1.0.0 (we rely on 0.1.0+) provide most symbols we care about, but
90 * unfortunately not all until 0.7.0. See bpf-compat.h for more details.
91 * Once we consider we can assume 0.7+ is present we can just use the same symbol
92 * list for both files, and when we assume 1.0+ is present we can remove this dlopen */
bd4beaa2 93 dl = dlopen("libbpf.so.0", RTLD_NOW|RTLD_NODELETE);
87e462f7 94 if (!dl)
4d2b9abb
YW
95 return cached = log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
96 "Neither libbpf.so.1 nor libbpf.so.0 are installed, cgroup BPF features disabled: %s",
97 dlerror());
87e462f7 98
dd6c0df6
LB
99 log_debug("Loaded 'libbpf.so.0' via dlopen()");
100
87e462f7 101 /* symbols deprecated in 1.0 we use as compat */
7736a71f
LP
102 r = dlsym_many_or_warn(
103 dl, LOG_DEBUG,
104#if MODERN_LIBBPF
105 /* Don't exist anymore in new libbpf, hence cannot type check them */
df80d728 106 DLSYM_ARG_FORCE(bpf_create_map)
7736a71f 107#else
df80d728 108 DLSYM_ARG(bpf_create_map)
7736a71f 109#endif
e5d4adb1 110 );
0f716ace
LP
111
112 /* NB: we don't try to load bpf_object__next_map() on old versions */
87e462f7 113 } else {
dd6c0df6
LB
114 log_debug("Loaded 'libbpf.so.1' via dlopen()");
115
87e462f7 116 /* symbols available from 0.7.0 */
7736a71f
LP
117 r = dlsym_many_or_warn(
118 dl, LOG_DEBUG,
119#if MODERN_LIBBPF
87e462f7 120 DLSYM_ARG(bpf_map_create),
0f716ace 121 DLSYM_ARG(bpf_object__next_map)
7736a71f
LP
122#else
123 /* These symbols did not exist in old libbpf, hence we cannot type check them */
124 DLSYM_ARG_FORCE(bpf_map_create),
0f716ace 125 DLSYM_ARG_FORCE(bpf_object__next_map)
7736a71f
LP
126#endif
127 );
87e462f7 128 }
e5d4adb1 129 if (r < 0)
4d2b9abb 130 return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m");
87e462f7
DM
131
132 r = dlsym_many_or_warn(
133 dl, LOG_DEBUG,
c5fd89ad
LB
134 DLSYM_ARG(bpf_link__destroy),
135 DLSYM_ARG(bpf_link__fd),
0f716ace
LP
136 DLSYM_ARG(bpf_link__open),
137 DLSYM_ARG(bpf_link__pin),
c5fd89ad
LB
138 DLSYM_ARG(bpf_map__fd),
139 DLSYM_ARG(bpf_map__name),
0f716ace 140 DLSYM_ARG(bpf_map__set_inner_map_fd),
6b8085db 141 DLSYM_ARG(bpf_map__set_max_entries),
0f716ace 142 DLSYM_ARG(bpf_map__set_pin_path),
510cdbeb 143 DLSYM_ARG(bpf_map_delete_elem),
0f716ace
LP
144 DLSYM_ARG(bpf_map_get_fd_by_id),
145 DLSYM_ARG(bpf_map_lookup_elem),
146 DLSYM_ARG(bpf_map_update_elem),
c5fd89ad 147 DLSYM_ARG(bpf_object__attach_skeleton),
c5fd89ad 148 DLSYM_ARG(bpf_object__destroy_skeleton),
0f716ace
LP
149 DLSYM_ARG(bpf_object__detach_skeleton),
150 DLSYM_ARG(bpf_object__load_skeleton),
151 DLSYM_ARG(bpf_object__name),
152 DLSYM_ARG(bpf_object__open_skeleton),
153 DLSYM_ARG(bpf_object__pin_maps),
7736a71f 154#if MODERN_LIBBPF
0f716ace 155 DLSYM_ARG(bpf_program__attach),
c5fd89ad 156 DLSYM_ARG(bpf_program__attach_cgroup),
510cdbeb 157 DLSYM_ARG(bpf_program__attach_lsm),
7736a71f
LP
158#else
159 /* libbpf added a "const" to function parameters where it should not have, ignore this type incompatibility */
0f716ace 160 DLSYM_ARG_FORCE(bpf_program__attach),
7736a71f
LP
161 DLSYM_ARG_FORCE(bpf_program__attach_cgroup),
162 DLSYM_ARG_FORCE(bpf_program__attach_lsm),
163#endif
c5fd89ad 164 DLSYM_ARG(bpf_program__name),
0f716ace 165 DLSYM_ARG(libbpf_get_error),
44005a57 166 DLSYM_ARG(libbpf_set_print),
0f716ace
LP
167 DLSYM_ARG(ring_buffer__epoll_fd),
168 DLSYM_ARG(ring_buffer__free),
169 DLSYM_ARG(ring_buffer__new),
170 DLSYM_ARG(ring_buffer__poll));
44005a57 171 if (r < 0)
4d2b9abb 172 return cached = log_full_errno(log_level, r, "Failed to load libbpf symbols, cgroup BPF features disabled: %m");
44005a57
ZJS
173
174 /* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */
175 (void) sym_libbpf_set_print(bpf_print_func);
7736a71f
LP
176
177 REENABLE_WARNING;
178
4d2b9abb 179 return cached = true;
c5fd89ad
LB
180}
181
8e495bf0
LB
182int bpf_get_error_translated(const void *ptr) {
183 int r;
184
185 r = sym_libbpf_get_error(ptr);
186
187 switch (r) {
188 case -524:
189 /* Workaround for kernel bug, BPF returns an internal error instead of translating it, until
190 * it is fixed:
191 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/errno.h?h=v6.9&id=a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6#n27
192 */
193 return -EOPNOTSUPP;
194 default:
195 return r;
196 }
197}
198
c5fd89ad
LB
199#else
200
4d2b9abb
YW
201int dlopen_bpf_full(int log_level) {
202 return log_once_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
203 "libbpf support is not compiled in, cgroup BPF features disabled.");
c5fd89ad
LB
204}
205#endif