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