]>
Commit | Line | Data |
---|---|---|
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 |
20 | DLSYM_PROTOTYPE(bpf_link__destroy) = NULL; |
21 | DLSYM_PROTOTYPE(bpf_link__fd) = NULL; | |
22 | DLSYM_PROTOTYPE(bpf_link__open) = NULL; | |
23 | DLSYM_PROTOTYPE(bpf_link__pin) = NULL; | |
24 | DLSYM_PROTOTYPE(bpf_map__fd) = NULL; | |
25 | DLSYM_PROTOTYPE(bpf_map__name) = NULL; | |
26 | DLSYM_PROTOTYPE(bpf_map__set_inner_map_fd) = NULL; | |
27 | DLSYM_PROTOTYPE(bpf_map__set_max_entries) = NULL; | |
28 | DLSYM_PROTOTYPE(bpf_map__set_pin_path) = NULL; | |
29 | DLSYM_PROTOTYPE(bpf_map_delete_elem) = NULL; | |
30 | DLSYM_PROTOTYPE(bpf_map_get_fd_by_id) = NULL; | |
31 | DLSYM_PROTOTYPE(bpf_map_lookup_elem) = NULL; | |
32 | DLSYM_PROTOTYPE(bpf_map_update_elem) = NULL; | |
33 | DLSYM_PROTOTYPE(bpf_object__attach_skeleton) = NULL; | |
34 | DLSYM_PROTOTYPE(bpf_object__destroy_skeleton) = NULL; | |
35 | DLSYM_PROTOTYPE(bpf_object__detach_skeleton) = NULL; | |
36 | DLSYM_PROTOTYPE(bpf_object__load_skeleton) = NULL; | |
37 | DLSYM_PROTOTYPE(bpf_object__name) = NULL; | |
38 | DLSYM_PROTOTYPE(bpf_object__open_skeleton) = NULL; | |
39 | DLSYM_PROTOTYPE(bpf_object__pin_maps) = NULL; | |
40 | DLSYM_PROTOTYPE(bpf_program__attach) = NULL; | |
41 | DLSYM_PROTOTYPE(bpf_program__attach_cgroup) = NULL; | |
42 | DLSYM_PROTOTYPE(bpf_program__attach_lsm) = NULL; | |
43 | DLSYM_PROTOTYPE(bpf_program__name) = NULL; | |
44 | DLSYM_PROTOTYPE(libbpf_get_error) = NULL; | |
45 | DLSYM_PROTOTYPE(libbpf_set_print) = NULL; | |
46 | DLSYM_PROTOTYPE(ring_buffer__epoll_fd) = NULL; | |
47 | DLSYM_PROTOTYPE(ring_buffer__free) = NULL; | |
48 | DLSYM_PROTOTYPE(ring_buffer__new) = NULL; | |
49 | DLSYM_PROTOTYPE(ring_buffer__poll) = NULL; | |
9dbabd0a LP |
50 | |
51 | /* new symbols available from libbpf 0.7.0 */ | |
6b8085db | 52 | int (*sym_bpf_map_create)(enum bpf_map_type, const char *, __u32, __u32, __u32, const struct bpf_map_create_opts *); |
0f716ace | 53 | struct 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 */ |
56 | int (*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) |
59 | static 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 |
72 | int 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 |
182 | int 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 |
201 | int 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 |