]> git.proxmox.com Git - mirror_iproute2.git/blob - lib/bpf_libbpf.c
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
[mirror_iproute2.git] / lib / bpf_libbpf.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * bpf_libbpf.c BPF code relay on libbpf
4 * Authors: Hangbin Liu <haliu@redhat.com>
5 *
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <errno.h>
15 #include <fcntl.h>
16
17 #include <libelf.h>
18 #include <gelf.h>
19
20 #include <bpf/libbpf.h>
21 #include <bpf/bpf.h>
22
23 #include "bpf_util.h"
24
25 static int verbose_print(enum libbpf_print_level level, const char *format, va_list args)
26 {
27 return vfprintf(stderr, format, args);
28 }
29
30 static int silent_print(enum libbpf_print_level level, const char *format, va_list args)
31 {
32 if (level > LIBBPF_WARN)
33 return 0;
34
35 /* Skip warning from bpf_object__init_user_maps() for legacy maps */
36 if (strstr(format, "has unrecognized, non-zero options"))
37 return 0;
38
39 return vfprintf(stderr, format, args);
40 }
41
42 static const char *get_bpf_program__section_name(const struct bpf_program *prog)
43 {
44 #ifdef HAVE_LIBBPF_SECTION_NAME
45 return bpf_program__section_name(prog);
46 #else
47 return bpf_program__title(prog, false);
48 #endif
49 }
50
51 static int create_map(const char *name, struct bpf_elf_map *map,
52 __u32 ifindex, int inner_fd)
53 {
54 struct bpf_create_map_attr map_attr = {};
55
56 map_attr.name = name;
57 map_attr.map_type = map->type;
58 map_attr.map_flags = map->flags;
59 map_attr.key_size = map->size_key;
60 map_attr.value_size = map->size_value;
61 map_attr.max_entries = map->max_elem;
62 map_attr.map_ifindex = ifindex;
63 map_attr.inner_map_fd = inner_fd;
64
65 return bpf_create_map_xattr(&map_attr);
66 }
67
68 static int create_map_in_map(struct bpf_object *obj, struct bpf_map *map,
69 struct bpf_elf_map *elf_map, int inner_fd,
70 bool *reuse_pin_map)
71 {
72 char pathname[PATH_MAX];
73 const char *map_name;
74 bool pin_map = false;
75 int map_fd, ret = 0;
76
77 map_name = bpf_map__name(map);
78
79 if (iproute2_is_pin_map(map_name, pathname)) {
80 pin_map = true;
81
82 /* Check if there already has a pinned map */
83 map_fd = bpf_obj_get(pathname);
84 if (map_fd > 0) {
85 if (reuse_pin_map)
86 *reuse_pin_map = true;
87 close(map_fd);
88 return bpf_map__set_pin_path(map, pathname);
89 }
90 }
91
92 map_fd = create_map(map_name, elf_map, bpf_map__ifindex(map), inner_fd);
93 if (map_fd < 0) {
94 fprintf(stderr, "create map %s failed\n", map_name);
95 return map_fd;
96 }
97
98 ret = bpf_map__reuse_fd(map, map_fd);
99 if (ret < 0) {
100 fprintf(stderr, "map %s reuse fd failed\n", map_name);
101 goto err_out;
102 }
103
104 if (pin_map) {
105 ret = bpf_map__set_pin_path(map, pathname);
106 if (ret < 0)
107 goto err_out;
108 }
109
110 return 0;
111 err_out:
112 close(map_fd);
113 return ret;
114 }
115
116 static int
117 handle_legacy_map_in_map(struct bpf_object *obj, struct bpf_map *inner_map,
118 const char *inner_map_name)
119 {
120 int inner_fd, outer_fd, inner_idx, ret = 0;
121 struct bpf_elf_map imap, omap;
122 struct bpf_map *outer_map;
123 /* What's the size limit of map name? */
124 char outer_map_name[128];
125 bool reuse_pin_map = false;
126
127 /* Deal with map-in-map */
128 if (iproute2_is_map_in_map(inner_map_name, &imap, &omap, outer_map_name)) {
129 ret = create_map_in_map(obj, inner_map, &imap, -1, NULL);
130 if (ret < 0)
131 return ret;
132
133 inner_fd = bpf_map__fd(inner_map);
134 outer_map = bpf_object__find_map_by_name(obj, outer_map_name);
135 ret = create_map_in_map(obj, outer_map, &omap, inner_fd, &reuse_pin_map);
136 if (ret < 0)
137 return ret;
138
139 if (!reuse_pin_map) {
140 inner_idx = imap.inner_idx;
141 outer_fd = bpf_map__fd(outer_map);
142 ret = bpf_map_update_elem(outer_fd, &inner_idx, &inner_fd, 0);
143 if (ret < 0)
144 fprintf(stderr, "Cannot update inner_idx into outer_map\n");
145 }
146 }
147
148 return ret;
149 }
150
151 static int find_legacy_tail_calls(struct bpf_program *prog, struct bpf_object *obj)
152 {
153 unsigned int map_id, key_id;
154 const char *sec_name;
155 struct bpf_map *map;
156 char map_name[128];
157 int ret;
158
159 /* Handle iproute2 tail call */
160 sec_name = get_bpf_program__section_name(prog);
161 ret = sscanf(sec_name, "%i/%i", &map_id, &key_id);
162 if (ret != 2)
163 return -1;
164
165 ret = iproute2_find_map_name_by_id(map_id, map_name);
166 if (ret < 0) {
167 fprintf(stderr, "unable to find map id %u for tail call\n", map_id);
168 return ret;
169 }
170
171 map = bpf_object__find_map_by_name(obj, map_name);
172 if (!map)
173 return -1;
174
175 /* Save the map here for later updating */
176 bpf_program__set_priv(prog, map, NULL);
177
178 return 0;
179 }
180
181 static int update_legacy_tail_call_maps(struct bpf_object *obj)
182 {
183 int prog_fd, map_fd, ret = 0;
184 unsigned int map_id, key_id;
185 struct bpf_program *prog;
186 const char *sec_name;
187 struct bpf_map *map;
188
189 bpf_object__for_each_program(prog, obj) {
190 map = bpf_program__priv(prog);
191 if (!map)
192 continue;
193
194 prog_fd = bpf_program__fd(prog);
195 if (prog_fd < 0)
196 continue;
197
198 sec_name = get_bpf_program__section_name(prog);
199 ret = sscanf(sec_name, "%i/%i", &map_id, &key_id);
200 if (ret != 2)
201 continue;
202
203 map_fd = bpf_map__fd(map);
204 ret = bpf_map_update_elem(map_fd, &key_id, &prog_fd, 0);
205 if (ret < 0) {
206 fprintf(stderr, "Cannot update map key for tail call!\n");
207 return ret;
208 }
209 }
210
211 return 0;
212 }
213
214 static int handle_legacy_maps(struct bpf_object *obj)
215 {
216 char pathname[PATH_MAX];
217 struct bpf_map *map;
218 const char *map_name;
219 int map_fd, ret = 0;
220
221 bpf_object__for_each_map(map, obj) {
222 map_name = bpf_map__name(map);
223
224 ret = handle_legacy_map_in_map(obj, map, map_name);
225 if (ret)
226 return ret;
227
228 /* If it is a iproute2 legacy pin maps, just set pin path
229 * and let bpf_object__load() to deal with the map creation.
230 * We need to ignore map-in-maps which have pinned maps manually
231 */
232 map_fd = bpf_map__fd(map);
233 if (map_fd < 0 && iproute2_is_pin_map(map_name, pathname)) {
234 ret = bpf_map__set_pin_path(map, pathname);
235 if (ret) {
236 fprintf(stderr, "map '%s': couldn't set pin path.\n", map_name);
237 break;
238 }
239 }
240
241 }
242
243 return ret;
244 }
245
246 static int load_bpf_object(struct bpf_cfg_in *cfg)
247 {
248 struct bpf_program *p, *prog = NULL;
249 struct bpf_object *obj;
250 char root_path[PATH_MAX];
251 struct bpf_map *map;
252 int prog_fd, ret = 0;
253
254 ret = iproute2_get_root_path(root_path, PATH_MAX);
255 if (ret)
256 return ret;
257
258 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
259 .relaxed_maps = true,
260 .pin_root_path = root_path,
261 );
262
263 obj = bpf_object__open_file(cfg->object, &open_opts);
264 if (libbpf_get_error(obj)) {
265 fprintf(stderr, "ERROR: opening BPF object file failed\n");
266 return -ENOENT;
267 }
268
269 bpf_object__for_each_program(p, obj) {
270 /* Only load the programs that will either be subsequently
271 * attached or inserted into a tail call map */
272 if (find_legacy_tail_calls(p, obj) < 0 && cfg->section &&
273 strcmp(get_bpf_program__section_name(p), cfg->section)) {
274 ret = bpf_program__set_autoload(p, false);
275 if (ret)
276 return -EINVAL;
277 continue;
278 }
279
280 bpf_program__set_type(p, cfg->type);
281 bpf_program__set_ifindex(p, cfg->ifindex);
282 if (!prog)
283 prog = p;
284 }
285
286 bpf_object__for_each_map(map, obj) {
287 if (!bpf_map__is_offload_neutral(map))
288 bpf_map__set_ifindex(map, cfg->ifindex);
289 }
290
291 if (!prog) {
292 fprintf(stderr, "object file doesn't contain sec %s\n", cfg->section);
293 return -ENOENT;
294 }
295
296 /* Handle iproute2 legacy pin maps and map-in-maps */
297 ret = handle_legacy_maps(obj);
298 if (ret)
299 goto unload_obj;
300
301 ret = bpf_object__load(obj);
302 if (ret)
303 goto unload_obj;
304
305 ret = update_legacy_tail_call_maps(obj);
306 if (ret)
307 goto unload_obj;
308
309 prog_fd = fcntl(bpf_program__fd(prog), F_DUPFD_CLOEXEC, 1);
310 if (prog_fd < 0)
311 ret = -errno;
312 else
313 cfg->prog_fd = prog_fd;
314
315 unload_obj:
316 /* Close obj as we don't need it */
317 bpf_object__close(obj);
318 return ret;
319 }
320
321 /* Load ebpf and return prog fd */
322 int iproute2_load_libbpf(struct bpf_cfg_in *cfg)
323 {
324 int ret = 0;
325
326 if (cfg->verbose)
327 libbpf_set_print(verbose_print);
328 else
329 libbpf_set_print(silent_print);
330
331 ret = iproute2_bpf_elf_ctx_init(cfg);
332 if (ret < 0) {
333 fprintf(stderr, "Cannot initialize ELF context!\n");
334 return ret;
335 }
336
337 ret = iproute2_bpf_fetch_ancillary();
338 if (ret < 0) {
339 fprintf(stderr, "Error fetching ELF ancillary data!\n");
340 return ret;
341 }
342
343 ret = load_bpf_object(cfg);
344 if (ret)
345 return ret;
346
347 return cfg->prog_fd;
348 }