1
2
3
4#define _GNU_SOURCE
5#include <ctype.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <ftw.h>
9#include <libgen.h>
10#include <mntent.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#include <linux/limits.h>
17#include <linux/magic.h>
18#include <net/if.h>
19#include <sys/mount.h>
20#include <sys/resource.h>
21#include <sys/stat.h>
22#include <sys/vfs.h>
23
24#include <bpf/bpf.h>
25#include <bpf/libbpf.h>
26
27#include "main.h"
28
29#ifndef BPF_FS_MAGIC
30#define BPF_FS_MAGIC 0xcafe4a11
31#endif
32
33const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
34 [BPF_CGROUP_INET_INGRESS] = "ingress",
35 [BPF_CGROUP_INET_EGRESS] = "egress",
36 [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
37 [BPF_CGROUP_INET_SOCK_RELEASE] = "sock_release",
38 [BPF_CGROUP_SOCK_OPS] = "sock_ops",
39 [BPF_CGROUP_DEVICE] = "device",
40 [BPF_CGROUP_INET4_BIND] = "bind4",
41 [BPF_CGROUP_INET6_BIND] = "bind6",
42 [BPF_CGROUP_INET4_CONNECT] = "connect4",
43 [BPF_CGROUP_INET6_CONNECT] = "connect6",
44 [BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
45 [BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
46 [BPF_CGROUP_INET4_GETPEERNAME] = "getpeername4",
47 [BPF_CGROUP_INET6_GETPEERNAME] = "getpeername6",
48 [BPF_CGROUP_INET4_GETSOCKNAME] = "getsockname4",
49 [BPF_CGROUP_INET6_GETSOCKNAME] = "getsockname6",
50 [BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
51 [BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
52 [BPF_CGROUP_SYSCTL] = "sysctl",
53 [BPF_CGROUP_UDP4_RECVMSG] = "recvmsg4",
54 [BPF_CGROUP_UDP6_RECVMSG] = "recvmsg6",
55 [BPF_CGROUP_GETSOCKOPT] = "getsockopt",
56 [BPF_CGROUP_SETSOCKOPT] = "setsockopt",
57
58 [BPF_SK_SKB_STREAM_PARSER] = "sk_skb_stream_parser",
59 [BPF_SK_SKB_STREAM_VERDICT] = "sk_skb_stream_verdict",
60 [BPF_SK_SKB_VERDICT] = "sk_skb_verdict",
61 [BPF_SK_MSG_VERDICT] = "sk_msg_verdict",
62 [BPF_LIRC_MODE2] = "lirc_mode2",
63 [BPF_FLOW_DISSECTOR] = "flow_dissector",
64 [BPF_TRACE_RAW_TP] = "raw_tp",
65 [BPF_TRACE_FENTRY] = "fentry",
66 [BPF_TRACE_FEXIT] = "fexit",
67 [BPF_MODIFY_RETURN] = "mod_ret",
68 [BPF_LSM_MAC] = "lsm_mac",
69 [BPF_SK_LOOKUP] = "sk_lookup",
70 [BPF_TRACE_ITER] = "trace_iter",
71 [BPF_XDP_DEVMAP] = "xdp_devmap",
72 [BPF_XDP_CPUMAP] = "xdp_cpumap",
73 [BPF_XDP] = "xdp",
74 [BPF_SK_REUSEPORT_SELECT] = "sk_skb_reuseport_select",
75 [BPF_SK_REUSEPORT_SELECT_OR_MIGRATE] = "sk_skb_reuseport_select_or_migrate",
76};
77
78void p_err(const char *fmt, ...)
79{
80 va_list ap;
81
82 va_start(ap, fmt);
83 if (json_output) {
84 jsonw_start_object(json_wtr);
85 jsonw_name(json_wtr, "error");
86 jsonw_vprintf_enquote(json_wtr, fmt, ap);
87 jsonw_end_object(json_wtr);
88 } else {
89 fprintf(stderr, "Error: ");
90 vfprintf(stderr, fmt, ap);
91 fprintf(stderr, "\n");
92 }
93 va_end(ap);
94}
95
96void p_info(const char *fmt, ...)
97{
98 va_list ap;
99
100 if (json_output)
101 return;
102
103 va_start(ap, fmt);
104 vfprintf(stderr, fmt, ap);
105 fprintf(stderr, "\n");
106 va_end(ap);
107}
108
109static bool is_bpffs(char *path)
110{
111 struct statfs st_fs;
112
113 if (statfs(path, &st_fs) < 0)
114 return false;
115
116 return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
117}
118
119void set_max_rlimit(void)
120{
121 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
122
123 setrlimit(RLIMIT_MEMLOCK, &rinf);
124}
125
126static int
127mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
128{
129 bool bind_done = false;
130
131 while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
132 if (errno != EINVAL || bind_done) {
133 snprintf(buff, bufflen,
134 "mount --make-private %s failed: %s",
135 target, strerror(errno));
136 return -1;
137 }
138
139 if (mount(target, target, "none", MS_BIND, NULL)) {
140 snprintf(buff, bufflen,
141 "mount --bind %s %s failed: %s",
142 target, target, strerror(errno));
143 return -1;
144 }
145
146 bind_done = true;
147 }
148
149 if (mount(type, target, type, 0, "mode=0700")) {
150 snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
151 type, type, target, strerror(errno));
152 return -1;
153 }
154
155 return 0;
156}
157
158int mount_tracefs(const char *target)
159{
160 char err_str[ERR_MAX_LEN];
161 int err;
162
163 err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
164 if (err) {
165 err_str[ERR_MAX_LEN - 1] = '\0';
166 p_err("can't mount tracefs: %s", err_str);
167 }
168
169 return err;
170}
171
172int open_obj_pinned(const char *path, bool quiet)
173{
174 char *pname;
175 int fd = -1;
176
177 pname = strdup(path);
178 if (!pname) {
179 if (!quiet)
180 p_err("mem alloc failed");
181 goto out_ret;
182 }
183
184 fd = bpf_obj_get(pname);
185 if (fd < 0) {
186 if (!quiet)
187 p_err("bpf obj get (%s): %s", pname,
188 errno == EACCES && !is_bpffs(dirname(pname)) ?
189 "directory not in bpf file system (bpffs)" :
190 strerror(errno));
191 goto out_free;
192 }
193
194out_free:
195 free(pname);
196out_ret:
197 return fd;
198}
199
200int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
201{
202 enum bpf_obj_type type;
203 int fd;
204
205 fd = open_obj_pinned(path, false);
206 if (fd < 0)
207 return -1;
208
209 type = get_fd_type(fd);
210 if (type < 0) {
211 close(fd);
212 return type;
213 }
214 if (type != exp_type) {
215 p_err("incorrect object type: %s", get_fd_type_name(type));
216 close(fd);
217 return -1;
218 }
219
220 return fd;
221}
222
223int mount_bpffs_for_pin(const char *name)
224{
225 char err_str[ERR_MAX_LEN];
226 char *file;
227 char *dir;
228 int err = 0;
229
230 file = malloc(strlen(name) + 1);
231 if (!file) {
232 p_err("mem alloc failed");
233 return -1;
234 }
235
236 strcpy(file, name);
237 dir = dirname(file);
238
239 if (is_bpffs(dir))
240
241 goto out_free;
242
243 if (block_mount) {
244 p_err("no BPF file system found, not mounting it due to --nomount option");
245 err = -1;
246 goto out_free;
247 }
248
249 err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
250 if (err) {
251 err_str[ERR_MAX_LEN - 1] = '\0';
252 p_err("can't mount BPF file system to pin the object (%s): %s",
253 name, err_str);
254 }
255
256out_free:
257 free(file);
258 return err;
259}
260
261int do_pin_fd(int fd, const char *name)
262{
263 int err;
264
265 err = mount_bpffs_for_pin(name);
266 if (err)
267 return err;
268
269 err = bpf_obj_pin(fd, name);
270 if (err)
271 p_err("can't pin the object (%s): %s", name, strerror(errno));
272
273 return err;
274}
275
276int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
277{
278 int err;
279 int fd;
280
281 fd = get_fd(&argc, &argv);
282 if (fd < 0)
283 return fd;
284
285 err = do_pin_fd(fd, *argv);
286
287 close(fd);
288 return err;
289}
290
291const char *get_fd_type_name(enum bpf_obj_type type)
292{
293 static const char * const names[] = {
294 [BPF_OBJ_UNKNOWN] = "unknown",
295 [BPF_OBJ_PROG] = "prog",
296 [BPF_OBJ_MAP] = "map",
297 };
298
299 if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
300 return names[BPF_OBJ_UNKNOWN];
301
302 return names[type];
303}
304
305int get_fd_type(int fd)
306{
307 char path[PATH_MAX];
308 char buf[512];
309 ssize_t n;
310
311 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
312
313 n = readlink(path, buf, sizeof(buf));
314 if (n < 0) {
315 p_err("can't read link type: %s", strerror(errno));
316 return -1;
317 }
318 if (n == sizeof(path)) {
319 p_err("can't read link type: path too long!");
320 return -1;
321 }
322
323 if (strstr(buf, "bpf-map"))
324 return BPF_OBJ_MAP;
325 else if (strstr(buf, "bpf-prog"))
326 return BPF_OBJ_PROG;
327 else if (strstr(buf, "bpf-link"))
328 return BPF_OBJ_LINK;
329
330 return BPF_OBJ_UNKNOWN;
331}
332
333char *get_fdinfo(int fd, const char *key)
334{
335 char path[PATH_MAX];
336 char *line = NULL;
337 size_t line_n = 0;
338 ssize_t n;
339 FILE *fdi;
340
341 snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
342
343 fdi = fopen(path, "r");
344 if (!fdi)
345 return NULL;
346
347 while ((n = getline(&line, &line_n, fdi)) > 0) {
348 char *value;
349 int len;
350
351 if (!strstr(line, key))
352 continue;
353
354 fclose(fdi);
355
356 value = strchr(line, '\t');
357 if (!value || !value[1]) {
358 free(line);
359 return NULL;
360 }
361 value++;
362
363 len = strlen(value);
364 memmove(line, value, len);
365 line[len - 1] = '\0';
366
367 return line;
368 }
369
370 free(line);
371 fclose(fdi);
372 return NULL;
373}
374
375void print_data_json(uint8_t *data, size_t len)
376{
377 unsigned int i;
378
379 jsonw_start_array(json_wtr);
380 for (i = 0; i < len; i++)
381 jsonw_printf(json_wtr, "%d", data[i]);
382 jsonw_end_array(json_wtr);
383}
384
385void print_hex_data_json(uint8_t *data, size_t len)
386{
387 unsigned int i;
388
389 jsonw_start_array(json_wtr);
390 for (i = 0; i < len; i++)
391 jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
392 jsonw_end_array(json_wtr);
393}
394
395
396static struct pinned_obj_table *build_fn_table;
397static enum bpf_obj_type build_fn_type;
398
399static int do_build_table_cb(const char *fpath, const struct stat *sb,
400 int typeflag, struct FTW *ftwbuf)
401{
402 struct bpf_prog_info pinned_info;
403 __u32 len = sizeof(pinned_info);
404 struct pinned_obj *obj_node;
405 enum bpf_obj_type objtype;
406 int fd, err = 0;
407
408 if (typeflag != FTW_F)
409 goto out_ret;
410
411 fd = open_obj_pinned(fpath, true);
412 if (fd < 0)
413 goto out_ret;
414
415 objtype = get_fd_type(fd);
416 if (objtype != build_fn_type)
417 goto out_close;
418
419 memset(&pinned_info, 0, sizeof(pinned_info));
420 if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
421 goto out_close;
422
423 obj_node = calloc(1, sizeof(*obj_node));
424 if (!obj_node) {
425 err = -1;
426 goto out_close;
427 }
428
429 obj_node->id = pinned_info.id;
430 obj_node->path = strdup(fpath);
431 if (!obj_node->path) {
432 err = -1;
433 free(obj_node);
434 goto out_close;
435 }
436
437 hash_add(build_fn_table->table, &obj_node->hash, obj_node->id);
438out_close:
439 close(fd);
440out_ret:
441 return err;
442}
443
444int build_pinned_obj_table(struct pinned_obj_table *tab,
445 enum bpf_obj_type type)
446{
447 struct mntent *mntent = NULL;
448 FILE *mntfile = NULL;
449 int flags = FTW_PHYS;
450 int nopenfd = 16;
451 int err = 0;
452
453 mntfile = setmntent("/proc/mounts", "r");
454 if (!mntfile)
455 return -1;
456
457 build_fn_table = tab;
458 build_fn_type = type;
459
460 while ((mntent = getmntent(mntfile))) {
461 char *path = mntent->mnt_dir;
462
463 if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
464 continue;
465 err = nftw(path, do_build_table_cb, nopenfd, flags);
466 if (err)
467 break;
468 }
469 fclose(mntfile);
470 return err;
471}
472
473void delete_pinned_obj_table(struct pinned_obj_table *tab)
474{
475 struct pinned_obj *obj;
476 struct hlist_node *tmp;
477 unsigned int bkt;
478
479 hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
480 hash_del(&obj->hash);
481 free(obj->path);
482 free(obj);
483 }
484}
485
486unsigned int get_page_size(void)
487{
488 static int result;
489
490 if (!result)
491 result = getpagesize();
492 return result;
493}
494
495unsigned int get_possible_cpus(void)
496{
497 int cpus = libbpf_num_possible_cpus();
498
499 if (cpus < 0) {
500 p_err("Can't get # of possible cpus: %s", strerror(-cpus));
501 exit(-1);
502 }
503 return cpus;
504}
505
506static char *
507ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
508{
509 struct stat st;
510 int err;
511
512 err = stat("/proc/self/ns/net", &st);
513 if (err) {
514 p_err("Can't stat /proc/self: %s", strerror(errno));
515 return NULL;
516 }
517
518 if (st.st_dev != ns_dev || st.st_ino != ns_ino)
519 return NULL;
520
521 return if_indextoname(ifindex, buf);
522}
523
524static int read_sysfs_hex_int(char *path)
525{
526 char vendor_id_buf[8];
527 int len;
528 int fd;
529
530 fd = open(path, O_RDONLY);
531 if (fd < 0) {
532 p_err("Can't open %s: %s", path, strerror(errno));
533 return -1;
534 }
535
536 len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
537 close(fd);
538 if (len < 0) {
539 p_err("Can't read %s: %s", path, strerror(errno));
540 return -1;
541 }
542 if (len >= (int)sizeof(vendor_id_buf)) {
543 p_err("Value in %s too long", path);
544 return -1;
545 }
546
547 vendor_id_buf[len] = 0;
548
549 return strtol(vendor_id_buf, NULL, 0);
550}
551
552static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
553{
554 char full_path[64];
555
556 snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
557 devname, entry_name);
558
559 return read_sysfs_hex_int(full_path);
560}
561
562const char *
563ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
564 const char **opt)
565{
566 char devname[IF_NAMESIZE];
567 int vendor_id;
568 int device_id;
569
570 if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
571 p_err("Can't get net device name for ifindex %d: %s", ifindex,
572 strerror(errno));
573 return NULL;
574 }
575
576 vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
577 if (vendor_id < 0) {
578 p_err("Can't get device vendor id for %s", devname);
579 return NULL;
580 }
581
582 switch (vendor_id) {
583 case 0x19ee:
584 device_id = read_sysfs_netdev_hex_int(devname, "device");
585 if (device_id != 0x4000 &&
586 device_id != 0x6000 &&
587 device_id != 0x6003)
588 p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
589 *opt = "ctx4";
590 return "NFP-6xxx";
591 default:
592 p_err("Can't get bfd arch name for device vendor id 0x%04x",
593 vendor_id);
594 return NULL;
595 }
596}
597
598void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
599{
600 char name[IF_NAMESIZE];
601
602 if (!ifindex)
603 return;
604
605 printf(" offloaded_to ");
606 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
607 printf("%s", name);
608 else
609 printf("ifindex %u ns_dev %llu ns_ino %llu",
610 ifindex, ns_dev, ns_inode);
611}
612
613void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
614{
615 char name[IF_NAMESIZE];
616
617 if (!ifindex)
618 return;
619
620 jsonw_name(json_wtr, "dev");
621 jsonw_start_object(json_wtr);
622 jsonw_uint_field(json_wtr, "ifindex", ifindex);
623 jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
624 jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
625 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
626 jsonw_string_field(json_wtr, "ifname", name);
627 jsonw_end_object(json_wtr);
628}
629
630int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
631{
632 char *endptr;
633
634 NEXT_ARGP();
635
636 if (*val) {
637 p_err("%s already specified", what);
638 return -1;
639 }
640
641 *val = strtoul(**argv, &endptr, 0);
642 if (*endptr) {
643 p_err("can't parse %s as %s", **argv, what);
644 return -1;
645 }
646 NEXT_ARGP();
647
648 return 0;
649}
650
651int __printf(2, 0)
652print_all_levels(__maybe_unused enum libbpf_print_level level,
653 const char *format, va_list args)
654{
655 return vfprintf(stderr, format, args);
656}
657
658static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
659{
660 unsigned int id = 0;
661 int fd, nb_fds = 0;
662 void *tmp;
663 int err;
664
665 while (true) {
666 struct bpf_prog_info info = {};
667 __u32 len = sizeof(info);
668
669 err = bpf_prog_get_next_id(id, &id);
670 if (err) {
671 if (errno != ENOENT) {
672 p_err("%s", strerror(errno));
673 goto err_close_fds;
674 }
675 return nb_fds;
676 }
677
678 fd = bpf_prog_get_fd_by_id(id);
679 if (fd < 0) {
680 p_err("can't get prog by id (%u): %s",
681 id, strerror(errno));
682 goto err_close_fds;
683 }
684
685 err = bpf_obj_get_info_by_fd(fd, &info, &len);
686 if (err) {
687 p_err("can't get prog info (%u): %s",
688 id, strerror(errno));
689 goto err_close_fd;
690 }
691
692 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
693 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
694 close(fd);
695 continue;
696 }
697
698 if (nb_fds > 0) {
699 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
700 if (!tmp) {
701 p_err("failed to realloc");
702 goto err_close_fd;
703 }
704 *fds = tmp;
705 }
706 (*fds)[nb_fds++] = fd;
707 }
708
709err_close_fd:
710 close(fd);
711err_close_fds:
712 while (--nb_fds >= 0)
713 close((*fds)[nb_fds]);
714 return -1;
715}
716
717int prog_parse_fds(int *argc, char ***argv, int **fds)
718{
719 if (is_prefix(**argv, "id")) {
720 unsigned int id;
721 char *endptr;
722
723 NEXT_ARGP();
724
725 id = strtoul(**argv, &endptr, 0);
726 if (*endptr) {
727 p_err("can't parse %s as ID", **argv);
728 return -1;
729 }
730 NEXT_ARGP();
731
732 (*fds)[0] = bpf_prog_get_fd_by_id(id);
733 if ((*fds)[0] < 0) {
734 p_err("get by id (%u): %s", id, strerror(errno));
735 return -1;
736 }
737 return 1;
738 } else if (is_prefix(**argv, "tag")) {
739 unsigned char tag[BPF_TAG_SIZE];
740
741 NEXT_ARGP();
742
743 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
744 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
745 != BPF_TAG_SIZE) {
746 p_err("can't parse tag");
747 return -1;
748 }
749 NEXT_ARGP();
750
751 return prog_fd_by_nametag(tag, fds, true);
752 } else if (is_prefix(**argv, "name")) {
753 char *name;
754
755 NEXT_ARGP();
756
757 name = **argv;
758 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
759 p_err("can't parse name");
760 return -1;
761 }
762 NEXT_ARGP();
763
764 return prog_fd_by_nametag(name, fds, false);
765 } else if (is_prefix(**argv, "pinned")) {
766 char *path;
767
768 NEXT_ARGP();
769
770 path = **argv;
771 NEXT_ARGP();
772
773 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
774 if ((*fds)[0] < 0)
775 return -1;
776 return 1;
777 }
778
779 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
780 return -1;
781}
782
783int prog_parse_fd(int *argc, char ***argv)
784{
785 int *fds = NULL;
786 int nb_fds, fd;
787
788 fds = malloc(sizeof(int));
789 if (!fds) {
790 p_err("mem alloc failed");
791 return -1;
792 }
793 nb_fds = prog_parse_fds(argc, argv, &fds);
794 if (nb_fds != 1) {
795 if (nb_fds > 1) {
796 p_err("several programs match this handle");
797 while (nb_fds--)
798 close(fds[nb_fds]);
799 }
800 fd = -1;
801 goto exit_free;
802 }
803
804 fd = fds[0];
805exit_free:
806 free(fds);
807 return fd;
808}
809
810static int map_fd_by_name(char *name, int **fds)
811{
812 unsigned int id = 0;
813 int fd, nb_fds = 0;
814 void *tmp;
815 int err;
816
817 while (true) {
818 struct bpf_map_info info = {};
819 __u32 len = sizeof(info);
820
821 err = bpf_map_get_next_id(id, &id);
822 if (err) {
823 if (errno != ENOENT) {
824 p_err("%s", strerror(errno));
825 goto err_close_fds;
826 }
827 return nb_fds;
828 }
829
830 fd = bpf_map_get_fd_by_id(id);
831 if (fd < 0) {
832 p_err("can't get map by id (%u): %s",
833 id, strerror(errno));
834 goto err_close_fds;
835 }
836
837 err = bpf_obj_get_info_by_fd(fd, &info, &len);
838 if (err) {
839 p_err("can't get map info (%u): %s",
840 id, strerror(errno));
841 goto err_close_fd;
842 }
843
844 if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
845 close(fd);
846 continue;
847 }
848
849 if (nb_fds > 0) {
850 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
851 if (!tmp) {
852 p_err("failed to realloc");
853 goto err_close_fd;
854 }
855 *fds = tmp;
856 }
857 (*fds)[nb_fds++] = fd;
858 }
859
860err_close_fd:
861 close(fd);
862err_close_fds:
863 while (--nb_fds >= 0)
864 close((*fds)[nb_fds]);
865 return -1;
866}
867
868int map_parse_fds(int *argc, char ***argv, int **fds)
869{
870 if (is_prefix(**argv, "id")) {
871 unsigned int id;
872 char *endptr;
873
874 NEXT_ARGP();
875
876 id = strtoul(**argv, &endptr, 0);
877 if (*endptr) {
878 p_err("can't parse %s as ID", **argv);
879 return -1;
880 }
881 NEXT_ARGP();
882
883 (*fds)[0] = bpf_map_get_fd_by_id(id);
884 if ((*fds)[0] < 0) {
885 p_err("get map by id (%u): %s", id, strerror(errno));
886 return -1;
887 }
888 return 1;
889 } else if (is_prefix(**argv, "name")) {
890 char *name;
891
892 NEXT_ARGP();
893
894 name = **argv;
895 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
896 p_err("can't parse name");
897 return -1;
898 }
899 NEXT_ARGP();
900
901 return map_fd_by_name(name, fds);
902 } else if (is_prefix(**argv, "pinned")) {
903 char *path;
904
905 NEXT_ARGP();
906
907 path = **argv;
908 NEXT_ARGP();
909
910 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
911 if ((*fds)[0] < 0)
912 return -1;
913 return 1;
914 }
915
916 p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
917 return -1;
918}
919
920int map_parse_fd(int *argc, char ***argv)
921{
922 int *fds = NULL;
923 int nb_fds, fd;
924
925 fds = malloc(sizeof(int));
926 if (!fds) {
927 p_err("mem alloc failed");
928 return -1;
929 }
930 nb_fds = map_parse_fds(argc, argv, &fds);
931 if (nb_fds != 1) {
932 if (nb_fds > 1) {
933 p_err("several maps match this handle");
934 while (nb_fds--)
935 close(fds[nb_fds]);
936 }
937 fd = -1;
938 goto exit_free;
939 }
940
941 fd = fds[0];
942exit_free:
943 free(fds);
944 return fd;
945}
946
947int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
948{
949 int err;
950 int fd;
951
952 fd = map_parse_fd(argc, argv);
953 if (fd < 0)
954 return -1;
955
956 err = bpf_obj_get_info_by_fd(fd, info, info_len);
957 if (err) {
958 p_err("can't get map info: %s", strerror(errno));
959 close(fd);
960 return err;
961 }
962
963 return fd;
964}
965