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