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