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
272
273 if (find_legacy_tail_calls(p, obj) < 0 && cfg->section &&
274 strcmp(get_bpf_program__section_name(p), cfg->section)) {
275 ret = bpf_program__set_autoload(p, false);
276 if (ret)
277 return -EINVAL;
278 continue;
279 }
280
281 bpf_program__set_type(p, cfg->type);
282 bpf_program__set_ifindex(p, cfg->ifindex);
283 if (!prog)
284 prog = p;
285 }
286
287 bpf_object__for_each_map(map, obj) {
288 if (!bpf_map__is_offload_neutral(map))
289 bpf_map__set_ifindex(map, cfg->ifindex);
290 }
291
292 if (!prog) {
293 fprintf(stderr, "object file doesn't contain sec %s\n", cfg->section);
294 return -ENOENT;
295 }
296
297
298 ret = handle_legacy_maps(obj);
299 if (ret)
300 goto unload_obj;
301
302 ret = bpf_object__load(obj);
303 if (ret)
304 goto unload_obj;
305
306 ret = update_legacy_tail_call_maps(obj);
307 if (ret)
308 goto unload_obj;
309
310 prog_fd = fcntl(bpf_program__fd(prog), F_DUPFD_CLOEXEC, 1);
311 if (prog_fd < 0)
312 ret = -errno;
313 else
314 cfg->prog_fd = prog_fd;
315
316unload_obj:
317
318 bpf_object__close(obj);
319 return ret;
320}
321
322
323int iproute2_load_libbpf(struct bpf_cfg_in *cfg)
324{
325 int ret = 0;
326
327 if (cfg->verbose)
328 libbpf_set_print(verbose_print);
329 else
330 libbpf_set_print(silent_print);
331
332 ret = iproute2_bpf_elf_ctx_init(cfg);
333 if (ret < 0) {
334 fprintf(stderr, "Cannot initialize ELF context!\n");
335 return ret;
336 }
337
338 ret = iproute2_bpf_fetch_ancillary();
339 if (ret < 0) {
340 fprintf(stderr, "Error fetching ELF ancillary data!\n");
341 return ret;
342 }
343
344 ret = load_bpf_object(cfg);
345 if (ret)
346 return ret;
347
348 return cfg->prog_fd;
349}
350