2018-12-13 11:59:25 +08:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
|
|
/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
#define _GNU_SOURCE
|
2018-05-04 09:37:15 +08:00
|
|
|
#include <ctype.h>
|
2017-10-05 11:10:04 +08:00
|
|
|
#include <errno.h>
|
2018-01-17 08:05:21 +08:00
|
|
|
#include <fcntl.h>
|
2020-07-21 10:48:16 +08:00
|
|
|
#include <ftw.h>
|
2017-10-05 11:10:04 +08:00
|
|
|
#include <libgen.h>
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
#include <mntent.h>
|
2017-10-05 11:10:04 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <linux/limits.h>
|
|
|
|
#include <linux/magic.h>
|
2017-12-28 10:39:10 +08:00
|
|
|
#include <net/if.h>
|
2017-10-25 11:11:28 +08:00
|
|
|
#include <sys/mount.h>
|
tools: bpftool: adjust rlimit RLIMIT_MEMLOCK when loading programs, maps
The limit for memory locked in the kernel by a process is usually set to
64 kbytes by default. This can be an issue when creating large BPF maps
and/or loading many programs. A workaround is to raise this limit for
the current process before trying to create a new BPF map. Changing the
hard limit requires the CAP_SYS_RESOURCE and can usually only be done by
root user (for non-root users, a call to setrlimit fails (and sets
errno) and the program simply goes on with its rlimit unchanged).
There is no API to get the current amount of memory locked for a user,
therefore we cannot raise the limit only when required. One solution,
used by bcc, is to try to create the map, and on getting a EPERM error,
raising the limit to infinity before giving another try. Another
approach, used in iproute2, is to raise the limit in all cases, before
trying to create the map.
Here we do the same as in iproute2: the rlimit is raised to infinity
before trying to load programs or to create maps with bpftool.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-07 20:29:30 +08:00
|
|
|
#include <sys/resource.h>
|
2017-12-28 10:39:10 +08:00
|
|
|
#include <sys/stat.h>
|
2017-10-05 11:10:04 +08:00
|
|
|
#include <sys/vfs.h>
|
|
|
|
|
2020-01-20 21:06:46 +08:00
|
|
|
#include <bpf/bpf.h>
|
|
|
|
#include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
2018-03-06 21:50:10 +08:00
|
|
|
#ifndef BPF_FS_MAGIC
|
|
|
|
#define BPF_FS_MAGIC 0xcafe4a11
|
|
|
|
#endif
|
|
|
|
|
2020-06-24 22:31:54 +08:00
|
|
|
const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
|
|
|
|
[BPF_CGROUP_INET_INGRESS] = "ingress",
|
|
|
|
[BPF_CGROUP_INET_EGRESS] = "egress",
|
|
|
|
[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
|
2020-07-07 07:01:27 +08:00
|
|
|
[BPF_CGROUP_INET_SOCK_RELEASE] = "sock_release",
|
2020-06-24 22:31:54 +08:00
|
|
|
[BPF_CGROUP_SOCK_OPS] = "sock_ops",
|
|
|
|
[BPF_CGROUP_DEVICE] = "device",
|
|
|
|
[BPF_CGROUP_INET4_BIND] = "bind4",
|
|
|
|
[BPF_CGROUP_INET6_BIND] = "bind6",
|
|
|
|
[BPF_CGROUP_INET4_CONNECT] = "connect4",
|
|
|
|
[BPF_CGROUP_INET6_CONNECT] = "connect6",
|
|
|
|
[BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
|
|
|
|
[BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
|
|
|
|
[BPF_CGROUP_INET4_GETPEERNAME] = "getpeername4",
|
|
|
|
[BPF_CGROUP_INET6_GETPEERNAME] = "getpeername6",
|
|
|
|
[BPF_CGROUP_INET4_GETSOCKNAME] = "getsockname4",
|
|
|
|
[BPF_CGROUP_INET6_GETSOCKNAME] = "getsockname6",
|
|
|
|
[BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
|
|
|
|
[BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
|
|
|
|
[BPF_CGROUP_SYSCTL] = "sysctl",
|
|
|
|
[BPF_CGROUP_UDP4_RECVMSG] = "recvmsg4",
|
|
|
|
[BPF_CGROUP_UDP6_RECVMSG] = "recvmsg6",
|
|
|
|
[BPF_CGROUP_GETSOCKOPT] = "getsockopt",
|
|
|
|
[BPF_CGROUP_SETSOCKOPT] = "setsockopt",
|
|
|
|
|
|
|
|
[BPF_SK_SKB_STREAM_PARSER] = "sk_skb_stream_parser",
|
|
|
|
[BPF_SK_SKB_STREAM_VERDICT] = "sk_skb_stream_verdict",
|
2021-03-31 10:32:30 +08:00
|
|
|
[BPF_SK_SKB_VERDICT] = "sk_skb_verdict",
|
2020-06-24 22:31:54 +08:00
|
|
|
[BPF_SK_MSG_VERDICT] = "sk_msg_verdict",
|
|
|
|
[BPF_LIRC_MODE2] = "lirc_mode2",
|
|
|
|
[BPF_FLOW_DISSECTOR] = "flow_dissector",
|
|
|
|
[BPF_TRACE_RAW_TP] = "raw_tp",
|
|
|
|
[BPF_TRACE_FENTRY] = "fentry",
|
|
|
|
[BPF_TRACE_FEXIT] = "fexit",
|
|
|
|
[BPF_MODIFY_RETURN] = "mod_ret",
|
|
|
|
[BPF_LSM_MAC] = "lsm_mac",
|
2020-07-17 18:35:34 +08:00
|
|
|
[BPF_SK_LOOKUP] = "sk_lookup",
|
2020-06-24 22:31:54 +08:00
|
|
|
};
|
|
|
|
|
2019-08-15 22:32:20 +08:00
|
|
|
void p_err(const char *fmt, ...)
|
2017-11-04 04:59:07 +08:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
jsonw_name(json_wtr, "error");
|
|
|
|
jsonw_vprintf_enquote(json_wtr, fmt, ap);
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Error: ");
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2019-08-15 22:32:20 +08:00
|
|
|
void p_info(const char *fmt, ...)
|
2017-11-04 04:59:07 +08:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static bool is_bpffs(char *path)
|
|
|
|
{
|
|
|
|
struct statfs st_fs;
|
|
|
|
|
|
|
|
if (statfs(path, &st_fs) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
|
|
|
|
}
|
|
|
|
|
tools: bpftool: adjust rlimit RLIMIT_MEMLOCK when loading programs, maps
The limit for memory locked in the kernel by a process is usually set to
64 kbytes by default. This can be an issue when creating large BPF maps
and/or loading many programs. A workaround is to raise this limit for
the current process before trying to create a new BPF map. Changing the
hard limit requires the CAP_SYS_RESOURCE and can usually only be done by
root user (for non-root users, a call to setrlimit fails (and sets
errno) and the program simply goes on with its rlimit unchanged).
There is no API to get the current amount of memory locked for a user,
therefore we cannot raise the limit only when required. One solution,
used by bcc, is to try to create the map, and on getting a EPERM error,
raising the limit to infinity before giving another try. Another
approach, used in iproute2, is to raise the limit in all cases, before
trying to create the map.
Here we do the same as in iproute2: the rlimit is raised to infinity
before trying to load programs or to create maps with bpftool.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-07 20:29:30 +08:00
|
|
|
void set_max_rlimit(void)
|
|
|
|
{
|
|
|
|
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
|
|
|
|
|
|
|
|
setrlimit(RLIMIT_MEMLOCK, &rinf);
|
|
|
|
}
|
|
|
|
|
2018-12-18 18:13:18 +08:00
|
|
|
static int
|
|
|
|
mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
|
2017-10-25 11:11:28 +08:00
|
|
|
{
|
|
|
|
bool bind_done = false;
|
|
|
|
|
|
|
|
while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
|
|
|
|
if (errno != EINVAL || bind_done) {
|
|
|
|
snprintf(buff, bufflen,
|
|
|
|
"mount --make-private %s failed: %s",
|
|
|
|
target, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mount(target, target, "none", MS_BIND, NULL)) {
|
|
|
|
snprintf(buff, bufflen,
|
|
|
|
"mount --bind %s %s failed: %s",
|
|
|
|
target, target, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bind_done = true;
|
|
|
|
}
|
|
|
|
|
2018-12-18 18:13:18 +08:00
|
|
|
if (mount(type, target, type, 0, "mode=0700")) {
|
|
|
|
snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
|
|
|
|
type, type, target, strerror(errno));
|
2017-10-25 11:11:28 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-18 18:13:18 +08:00
|
|
|
int mount_tracefs(const char *target)
|
|
|
|
{
|
|
|
|
char err_str[ERR_MAX_LEN];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
|
|
|
|
if (err) {
|
|
|
|
err_str[ERR_MAX_LEN - 1] = '\0';
|
|
|
|
p_err("can't mount tracefs: %s", err_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
int open_obj_pinned(const char *path, bool quiet)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
2020-07-21 10:48:16 +08:00
|
|
|
char *pname;
|
|
|
|
int fd = -1;
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
pname = strdup(path);
|
|
|
|
if (!pname) {
|
|
|
|
if (!quiet)
|
|
|
|
p_err("mem alloc failed");
|
|
|
|
goto out_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = bpf_obj_get(pname);
|
2017-10-05 11:10:04 +08:00
|
|
|
if (fd < 0) {
|
tools: bpftool: pass an argument to silence open_obj_pinned()
Function open_obj_pinned() prints error messages when it fails to open a
link in the BPF virtual file system. However, in some occasions it is
not desirable to print an error, for example when we parse all links
under the bpffs root, and the error is due to some paths actually being
symbolic links.
Example output:
# ls -l /sys/fs/bpf/
lrwxrwxrwx 1 root root 0 Oct 18 19:00 ip -> /sys/fs/bpf/tc/
drwx------ 3 root root 0 Oct 18 19:00 tc
lrwxrwxrwx 1 root root 0 Oct 18 19:00 xdp -> /sys/fs/bpf/tc/
# bpftool --bpffs prog show
Error: bpf obj get (/sys/fs/bpf): Permission denied
Error: bpf obj get (/sys/fs/bpf): Permission denied
# strace -e bpf bpftool --bpffs prog show
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/ip", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/xdp", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
...
To fix it, pass a bool as a second argument to the function, and prevent
it from printing an error when the argument is set to true.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-08 19:52:27 +08:00
|
|
|
if (!quiet)
|
2020-07-21 10:48:16 +08:00
|
|
|
p_err("bpf obj get (%s): %s", pname,
|
|
|
|
errno == EACCES && !is_bpffs(dirname(pname)) ?
|
tools: bpftool: pass an argument to silence open_obj_pinned()
Function open_obj_pinned() prints error messages when it fails to open a
link in the BPF virtual file system. However, in some occasions it is
not desirable to print an error, for example when we parse all links
under the bpffs root, and the error is due to some paths actually being
symbolic links.
Example output:
# ls -l /sys/fs/bpf/
lrwxrwxrwx 1 root root 0 Oct 18 19:00 ip -> /sys/fs/bpf/tc/
drwx------ 3 root root 0 Oct 18 19:00 tc
lrwxrwxrwx 1 root root 0 Oct 18 19:00 xdp -> /sys/fs/bpf/tc/
# bpftool --bpffs prog show
Error: bpf obj get (/sys/fs/bpf): Permission denied
Error: bpf obj get (/sys/fs/bpf): Permission denied
# strace -e bpf bpftool --bpffs prog show
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/ip", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/xdp", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
...
To fix it, pass a bool as a second argument to the function, and prevent
it from printing an error when the argument is set to true.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-08 19:52:27 +08:00
|
|
|
"directory not in bpf file system (bpffs)" :
|
|
|
|
strerror(errno));
|
2020-07-21 10:48:16 +08:00
|
|
|
goto out_free;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
out_free:
|
|
|
|
free(pname);
|
|
|
|
out_ret:
|
2017-11-08 12:55:47 +08:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
|
2017-11-08 12:55:47 +08:00
|
|
|
{
|
|
|
|
enum bpf_obj_type type;
|
|
|
|
int fd;
|
|
|
|
|
tools: bpftool: pass an argument to silence open_obj_pinned()
Function open_obj_pinned() prints error messages when it fails to open a
link in the BPF virtual file system. However, in some occasions it is
not desirable to print an error, for example when we parse all links
under the bpffs root, and the error is due to some paths actually being
symbolic links.
Example output:
# ls -l /sys/fs/bpf/
lrwxrwxrwx 1 root root 0 Oct 18 19:00 ip -> /sys/fs/bpf/tc/
drwx------ 3 root root 0 Oct 18 19:00 tc
lrwxrwxrwx 1 root root 0 Oct 18 19:00 xdp -> /sys/fs/bpf/tc/
# bpftool --bpffs prog show
Error: bpf obj get (/sys/fs/bpf): Permission denied
Error: bpf obj get (/sys/fs/bpf): Permission denied
# strace -e bpf bpftool --bpffs prog show
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/ip", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
bpf(BPF_OBJ_GET, {pathname="/sys/fs/bpf/xdp", bpf_fd=0}, 72) = -1 EACCES (Permission denied)
Error: bpf obj get (/sys/fs/bpf): Permission denied
...
To fix it, pass a bool as a second argument to the function, and prevent
it from printing an error when the argument is set to true.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-08 19:52:27 +08:00
|
|
|
fd = open_obj_pinned(path, false);
|
2017-11-08 12:55:47 +08:00
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
type = get_fd_type(fd);
|
|
|
|
if (type < 0) {
|
|
|
|
close(fd);
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
if (type != exp_type) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("incorrect object type: %s", get_fd_type_name(type));
|
2017-10-05 11:10:04 +08:00
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2018-11-10 00:21:44 +08:00
|
|
|
int mount_bpffs_for_pin(const char *name)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
2017-10-25 11:11:28 +08:00
|
|
|
char err_str[ERR_MAX_LEN];
|
|
|
|
char *file;
|
|
|
|
char *dir;
|
2017-12-13 23:18:53 +08:00
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
file = malloc(strlen(name) + 1);
|
|
|
|
strcpy(file, name);
|
|
|
|
dir = dirname(file);
|
|
|
|
|
2018-11-10 00:21:44 +08:00
|
|
|
if (is_bpffs(dir))
|
|
|
|
/* nothing to do if already mounted */
|
2017-12-13 23:18:53 +08:00
|
|
|
goto out_free;
|
|
|
|
|
2018-12-18 18:13:19 +08:00
|
|
|
if (block_mount) {
|
|
|
|
p_err("no BPF file system found, not mounting it due to --nomount option");
|
|
|
|
err = -1;
|
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2018-12-18 18:13:18 +08:00
|
|
|
err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
|
2018-11-10 00:21:44 +08:00
|
|
|
if (err) {
|
2017-12-13 23:18:53 +08:00
|
|
|
err_str[ERR_MAX_LEN - 1] = '\0';
|
|
|
|
p_err("can't mount BPF file system to pin the object (%s): %s",
|
|
|
|
name, err_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
out_free:
|
|
|
|
free(file);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-11-10 00:21:44 +08:00
|
|
|
int do_pin_fd(int fd, const char *name)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = mount_bpffs_for_pin(name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-08-07 08:19:23 +08:00
|
|
|
err = bpf_obj_pin(fd, name);
|
|
|
|
if (err)
|
|
|
|
p_err("can't pin the object (%s): %s", name, strerror(errno));
|
|
|
|
|
|
|
|
return err;
|
2018-11-10 00:21:44 +08:00
|
|
|
}
|
|
|
|
|
2020-03-13 02:46:07 +08:00
|
|
|
int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
|
2017-12-13 23:18:53 +08:00
|
|
|
{
|
2017-10-05 11:10:04 +08:00
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
2020-03-13 02:46:07 +08:00
|
|
|
fd = get_fd(&argc, &argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2017-12-13 23:18:53 +08:00
|
|
|
err = do_pin_fd(fd, *argv);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2017-10-25 11:11:28 +08:00
|
|
|
close(fd);
|
|
|
|
return err;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_fd_type_name(enum bpf_obj_type type)
|
|
|
|
{
|
|
|
|
static const char * const names[] = {
|
|
|
|
[BPF_OBJ_UNKNOWN] = "unknown",
|
|
|
|
[BPF_OBJ_PROG] = "prog",
|
|
|
|
[BPF_OBJ_MAP] = "map",
|
|
|
|
};
|
|
|
|
|
|
|
|
if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
|
|
|
|
return names[BPF_OBJ_UNKNOWN];
|
|
|
|
|
|
|
|
return names[type];
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_fd_type(int fd)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
char buf[512];
|
|
|
|
ssize_t n;
|
|
|
|
|
2018-12-01 00:25:44 +08:00
|
|
|
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
n = readlink(path, buf, sizeof(buf));
|
|
|
|
if (n < 0) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't read link type: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (n == sizeof(path)) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't read link type: path too long!");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(buf, "bpf-map"))
|
|
|
|
return BPF_OBJ_MAP;
|
|
|
|
else if (strstr(buf, "bpf-prog"))
|
|
|
|
return BPF_OBJ_PROG;
|
2020-04-29 08:16:12 +08:00
|
|
|
else if (strstr(buf, "bpf-link"))
|
|
|
|
return BPF_OBJ_LINK;
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
return BPF_OBJ_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *get_fdinfo(int fd, const char *key)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
char *line = NULL;
|
|
|
|
size_t line_n = 0;
|
|
|
|
ssize_t n;
|
|
|
|
FILE *fdi;
|
|
|
|
|
2018-12-01 00:25:44 +08:00
|
|
|
snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
fdi = fopen(path, "r");
|
2019-01-29 02:01:21 +08:00
|
|
|
if (!fdi)
|
2017-10-05 11:10:04 +08:00
|
|
|
return NULL;
|
|
|
|
|
2018-11-08 19:52:25 +08:00
|
|
|
while ((n = getline(&line, &line_n, fdi)) > 0) {
|
2017-10-05 11:10:04 +08:00
|
|
|
char *value;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!strstr(line, key))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fclose(fdi);
|
|
|
|
|
|
|
|
value = strchr(line, '\t');
|
|
|
|
if (!value || !value[1]) {
|
|
|
|
free(line);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
value++;
|
|
|
|
|
|
|
|
len = strlen(value);
|
|
|
|
memmove(line, value, len);
|
|
|
|
line[len - 1] = '\0';
|
|
|
|
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(line);
|
|
|
|
fclose(fdi);
|
|
|
|
return NULL;
|
|
|
|
}
|
tools: bpftool: add JSON output for `bpftool prog dump xlated *` command
Add a new printing function to dump translated eBPF instructions as
JSON. As for plain output, opcodes are printed only on request (when
`opcodes` is provided on the command line).
The disassembled output is generated by the same code that is used by
the kernel verifier.
Example output:
$ bpftool --json --pretty prog dump xlated id 1
[{
"disasm": "(bf) r6 = r1"
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)"
},{
"disasm": "(95) exit"
}
]
$ bpftool --json --pretty prog dump xlated id 1 opcodes
[{
"disasm": "(bf) r6 = r1",
"opcodes": {
"code": "0xbf",
"src_reg": "0x1",
"dst_reg": "0x6",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)",
"opcodes": {
"code": "0x61",
"src_reg": "0x6",
"dst_reg": "0x7",
"off": ["0x10","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(95) exit",
"opcodes": {
"code": "0x95",
"src_reg": "0x0",
"dst_reg": "0x0",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
}
]
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-24 00:24:10 +08:00
|
|
|
|
2018-05-04 09:37:16 +08:00
|
|
|
void print_data_json(uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
jsonw_printf(json_wtr, "%d", data[i]);
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
}
|
|
|
|
|
tools: bpftool: add JSON output for `bpftool prog dump xlated *` command
Add a new printing function to dump translated eBPF instructions as
JSON. As for plain output, opcodes are printed only on request (when
`opcodes` is provided on the command line).
The disassembled output is generated by the same code that is used by
the kernel verifier.
Example output:
$ bpftool --json --pretty prog dump xlated id 1
[{
"disasm": "(bf) r6 = r1"
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)"
},{
"disasm": "(95) exit"
}
]
$ bpftool --json --pretty prog dump xlated id 1 opcodes
[{
"disasm": "(bf) r6 = r1",
"opcodes": {
"code": "0xbf",
"src_reg": "0x1",
"dst_reg": "0x6",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)",
"opcodes": {
"code": "0x61",
"src_reg": "0x6",
"dst_reg": "0x7",
"off": ["0x10","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(95) exit",
"opcodes": {
"code": "0x95",
"src_reg": "0x0",
"dst_reg": "0x0",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
}
]
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-24 00:24:10 +08:00
|
|
|
void print_hex_data_json(uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
}
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
/* extra params for nftw cb */
|
|
|
|
static struct pinned_obj_table *build_fn_table;
|
|
|
|
static enum bpf_obj_type build_fn_type;
|
|
|
|
|
|
|
|
static int do_build_table_cb(const char *fpath, const struct stat *sb,
|
|
|
|
int typeflag, struct FTW *ftwbuf)
|
|
|
|
{
|
|
|
|
struct bpf_prog_info pinned_info;
|
|
|
|
__u32 len = sizeof(pinned_info);
|
|
|
|
struct pinned_obj *obj_node;
|
|
|
|
enum bpf_obj_type objtype;
|
|
|
|
int fd, err = 0;
|
|
|
|
|
|
|
|
if (typeflag != FTW_F)
|
|
|
|
goto out_ret;
|
|
|
|
|
|
|
|
fd = open_obj_pinned(fpath, true);
|
|
|
|
if (fd < 0)
|
|
|
|
goto out_ret;
|
|
|
|
|
|
|
|
objtype = get_fd_type(fd);
|
|
|
|
if (objtype != build_fn_type)
|
|
|
|
goto out_close;
|
|
|
|
|
|
|
|
memset(&pinned_info, 0, sizeof(pinned_info));
|
|
|
|
if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
|
|
|
|
goto out_close;
|
|
|
|
|
|
|
|
obj_node = calloc(1, sizeof(*obj_node));
|
|
|
|
if (!obj_node) {
|
|
|
|
err = -1;
|
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj_node->id = pinned_info.id;
|
|
|
|
obj_node->path = strdup(fpath);
|
|
|
|
if (!obj_node->path) {
|
|
|
|
err = -1;
|
|
|
|
free(obj_node);
|
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash_add(build_fn_table->table, &obj_node->hash, obj_node->id);
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
out_ret:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
int build_pinned_obj_table(struct pinned_obj_table *tab,
|
|
|
|
enum bpf_obj_type type)
|
|
|
|
{
|
|
|
|
struct mntent *mntent = NULL;
|
|
|
|
FILE *mntfile = NULL;
|
2020-07-21 10:48:16 +08:00
|
|
|
int flags = FTW_PHYS;
|
|
|
|
int nopenfd = 16;
|
|
|
|
int err = 0;
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
|
|
|
|
mntfile = setmntent("/proc/mounts", "r");
|
|
|
|
if (!mntfile)
|
|
|
|
return -1;
|
|
|
|
|
2020-07-21 10:48:16 +08:00
|
|
|
build_fn_table = tab;
|
|
|
|
build_fn_type = type;
|
|
|
|
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
while ((mntent = getmntent(mntfile))) {
|
2020-07-21 10:48:16 +08:00
|
|
|
char *path = mntent->mnt_dir;
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
|
|
|
|
if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
|
|
|
|
continue;
|
2020-07-21 10:48:16 +08:00
|
|
|
err = nftw(path, do_build_table_cb, nopenfd, flags);
|
|
|
|
if (err)
|
|
|
|
break;
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
}
|
|
|
|
fclose(mntfile);
|
2020-07-21 10:48:16 +08:00
|
|
|
return err;
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void delete_pinned_obj_table(struct pinned_obj_table *tab)
|
|
|
|
{
|
|
|
|
struct pinned_obj *obj;
|
|
|
|
struct hlist_node *tmp;
|
|
|
|
unsigned int bkt;
|
|
|
|
|
|
|
|
hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
|
|
|
|
hash_del(&obj->hash);
|
|
|
|
free(obj->path);
|
|
|
|
free(obj);
|
|
|
|
}
|
|
|
|
}
|
2017-12-28 10:39:10 +08:00
|
|
|
|
2018-05-04 09:37:16 +08:00
|
|
|
unsigned int get_page_size(void)
|
|
|
|
{
|
|
|
|
static int result;
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
result = getpagesize();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-05-04 09:37:15 +08:00
|
|
|
unsigned int get_possible_cpus(void)
|
|
|
|
{
|
2019-06-11 08:56:52 +08:00
|
|
|
int cpus = libbpf_num_possible_cpus();
|
2018-05-04 09:37:15 +08:00
|
|
|
|
2019-06-11 08:56:52 +08:00
|
|
|
if (cpus < 0) {
|
|
|
|
p_err("Can't get # of possible cpus: %s", strerror(-cpus));
|
2018-05-04 09:37:15 +08:00
|
|
|
exit(-1);
|
|
|
|
}
|
2019-06-11 08:56:52 +08:00
|
|
|
return cpus;
|
2018-05-04 09:37:15 +08:00
|
|
|
}
|
|
|
|
|
2017-12-28 10:39:10 +08:00
|
|
|
static char *
|
|
|
|
ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = stat("/proc/self/ns/net", &st);
|
|
|
|
if (err) {
|
|
|
|
p_err("Can't stat /proc/self: %s", strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (st.st_dev != ns_dev || st.st_ino != ns_ino)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return if_indextoname(ifindex, buf);
|
|
|
|
}
|
|
|
|
|
2018-01-17 08:05:21 +08:00
|
|
|
static int read_sysfs_hex_int(char *path)
|
|
|
|
{
|
|
|
|
char vendor_id_buf[8];
|
|
|
|
int len;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = open(path, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
p_err("Can't open %s: %s", path, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
|
|
|
|
close(fd);
|
|
|
|
if (len < 0) {
|
|
|
|
p_err("Can't read %s: %s", path, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (len >= (int)sizeof(vendor_id_buf)) {
|
|
|
|
p_err("Value in %s too long", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vendor_id_buf[len] = 0;
|
|
|
|
|
|
|
|
return strtol(vendor_id_buf, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
|
|
|
|
{
|
|
|
|
char full_path[64];
|
|
|
|
|
|
|
|
snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
|
|
|
|
devname, entry_name);
|
|
|
|
|
|
|
|
return read_sysfs_hex_int(full_path);
|
|
|
|
}
|
|
|
|
|
2018-10-19 02:34:55 +08:00
|
|
|
const char *
|
|
|
|
ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
|
|
|
|
const char **opt)
|
2018-01-17 08:05:21 +08:00
|
|
|
{
|
|
|
|
char devname[IF_NAMESIZE];
|
|
|
|
int vendor_id;
|
|
|
|
int device_id;
|
|
|
|
|
|
|
|
if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
|
|
|
|
p_err("Can't get net device name for ifindex %d: %s", ifindex,
|
|
|
|
strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
|
|
|
|
if (vendor_id < 0) {
|
|
|
|
p_err("Can't get device vendor id for %s", devname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (vendor_id) {
|
|
|
|
case 0x19ee:
|
|
|
|
device_id = read_sysfs_netdev_hex_int(devname, "device");
|
|
|
|
if (device_id != 0x4000 &&
|
|
|
|
device_id != 0x6000 &&
|
|
|
|
device_id != 0x6003)
|
|
|
|
p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
|
2018-10-19 02:34:55 +08:00
|
|
|
*opt = "ctx4";
|
2018-01-17 08:05:21 +08:00
|
|
|
return "NFP-6xxx";
|
|
|
|
default:
|
|
|
|
p_err("Can't get bfd arch name for device vendor id 0x%04x",
|
|
|
|
vendor_id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-28 10:39:10 +08:00
|
|
|
void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
|
|
|
|
{
|
|
|
|
char name[IF_NAMESIZE];
|
|
|
|
|
|
|
|
if (!ifindex)
|
|
|
|
return;
|
|
|
|
|
2018-12-01 00:25:47 +08:00
|
|
|
printf(" offloaded_to ");
|
2017-12-28 10:39:10 +08:00
|
|
|
if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
|
|
|
|
printf("%s", name);
|
|
|
|
else
|
|
|
|
printf("ifindex %u ns_dev %llu ns_ino %llu",
|
|
|
|
ifindex, ns_dev, ns_inode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
|
|
|
|
{
|
|
|
|
char name[IF_NAMESIZE];
|
|
|
|
|
|
|
|
if (!ifindex)
|
|
|
|
return;
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "dev");
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
jsonw_uint_field(json_wtr, "ifindex", ifindex);
|
|
|
|
jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
|
|
|
|
jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
|
|
|
|
if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
|
|
|
|
jsonw_string_field(json_wtr, "ifname", name);
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
2018-10-16 07:30:36 +08:00
|
|
|
|
|
|
|
int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
|
|
|
|
{
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
if (*val) {
|
|
|
|
p_err("%s already specified", what);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*val = strtoul(**argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
|
|
|
p_err("can't parse %s as %s", **argv, what);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
tools: bpftool: Restore message on failure to guess program type
In commit 4a3d6c6a6e4d ("libbpf: Reduce log level for custom section
names"), log level for messages for libbpf_attach_type_by_name() and
libbpf_prog_type_by_name() was downgraded from "info" to "debug". The
latter function, in particular, is used by bpftool when attempting to
load programs, and this change caused bpftool to exit with no hint or
error message when it fails to detect the type of the program to load
(unless "-d" option was provided).
To help users understand why bpftool fails to load the program, let's do
a second run of the function with log level in "debug" mode in case of
failure.
Before:
# bpftool prog load sample_ret0.o /sys/fs/bpf/sample_ret0
# echo $?
255
Or really verbose with -d flag:
# bpftool -d prog load sample_ret0.o /sys/fs/bpf/sample_ret0
libbpf: loading sample_ret0.o
libbpf: section(1) .strtab, size 134, link 0, flags 0, type=3
libbpf: skip section(1) .strtab
libbpf: section(2) .text, size 16, link 0, flags 6, type=1
libbpf: found program .text
libbpf: section(3) .debug_abbrev, size 55, link 0, flags 0, type=1
libbpf: skip section(3) .debug_abbrev
libbpf: section(4) .debug_info, size 75, link 0, flags 0, type=1
libbpf: skip section(4) .debug_info
libbpf: section(5) .rel.debug_info, size 32, link 14, flags 0, type=9
libbpf: skip relo .rel.debug_info(5) for section(4)
libbpf: section(6) .debug_str, size 150, link 0, flags 30, type=1
libbpf: skip section(6) .debug_str
libbpf: section(7) .BTF, size 155, link 0, flags 0, type=1
libbpf: section(8) .BTF.ext, size 80, link 0, flags 0, type=1
libbpf: section(9) .rel.BTF.ext, size 32, link 14, flags 0, type=9
libbpf: skip relo .rel.BTF.ext(9) for section(8)
libbpf: section(10) .debug_frame, size 40, link 0, flags 0, type=1
libbpf: skip section(10) .debug_frame
libbpf: section(11) .rel.debug_frame, size 16, link 14, flags 0, type=9
libbpf: skip relo .rel.debug_frame(11) for section(10)
libbpf: section(12) .debug_line, size 74, link 0, flags 0, type=1
libbpf: skip section(12) .debug_line
libbpf: section(13) .rel.debug_line, size 16, link 14, flags 0, type=9
libbpf: skip relo .rel.debug_line(13) for section(12)
libbpf: section(14) .symtab, size 96, link 1, flags 0, type=2
libbpf: looking for externs among 4 symbols...
libbpf: collected 0 externs total
libbpf: failed to guess program type from ELF section '.text'
libbpf: supported section(type) names are: socket sk_reuseport kprobe/ [...]
After:
# bpftool prog load sample_ret0.o /sys/fs/bpf/sample_ret0
libbpf: failed to guess program type from ELF section '.text'
libbpf: supported section(type) names are: socket sk_reuseport kprobe/ [...]
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20200311021205.9755-1-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2020-03-11 10:12:05 +08:00
|
|
|
|
|
|
|
int __printf(2, 0)
|
|
|
|
print_all_levels(__maybe_unused enum libbpf_print_level level,
|
|
|
|
const char *format, va_list args)
|
|
|
|
{
|
|
|
|
return vfprintf(stderr, format, args);
|
|
|
|
}
|
2020-06-20 07:16:58 +08:00
|
|
|
|
|
|
|
static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
|
|
|
|
{
|
|
|
|
unsigned int id = 0;
|
|
|
|
int fd, nb_fds = 0;
|
|
|
|
void *tmp;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
struct bpf_prog_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
|
|
|
|
err = bpf_prog_get_next_id(id, &id);
|
|
|
|
if (err) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
p_err("%s", strerror(errno));
|
|
|
|
goto err_close_fds;
|
|
|
|
}
|
|
|
|
return nb_fds;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = bpf_prog_get_fd_by_id(id);
|
|
|
|
if (fd < 0) {
|
|
|
|
p_err("can't get prog by id (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
goto err_close_fds;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get prog info (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
goto err_close_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
|
|
|
|
(!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nb_fds > 0) {
|
|
|
|
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
|
|
|
|
if (!tmp) {
|
|
|
|
p_err("failed to realloc");
|
|
|
|
goto err_close_fd;
|
|
|
|
}
|
|
|
|
*fds = tmp;
|
|
|
|
}
|
|
|
|
(*fds)[nb_fds++] = fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
err_close_fd:
|
|
|
|
close(fd);
|
|
|
|
err_close_fds:
|
|
|
|
while (--nb_fds >= 0)
|
|
|
|
close((*fds)[nb_fds]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prog_parse_fds(int *argc, char ***argv, int **fds)
|
|
|
|
{
|
|
|
|
if (is_prefix(**argv, "id")) {
|
|
|
|
unsigned int id;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
id = strtoul(**argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
|
|
|
p_err("can't parse %s as ID", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
(*fds)[0] = bpf_prog_get_fd_by_id(id);
|
|
|
|
if ((*fds)[0] < 0) {
|
|
|
|
p_err("get by id (%u): %s", id, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
} else if (is_prefix(**argv, "tag")) {
|
|
|
|
unsigned char tag[BPF_TAG_SIZE];
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
|
|
|
|
tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
|
|
|
|
!= BPF_TAG_SIZE) {
|
|
|
|
p_err("can't parse tag");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
return prog_fd_by_nametag(tag, fds, true);
|
|
|
|
} else if (is_prefix(**argv, "name")) {
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
name = **argv;
|
|
|
|
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
|
|
|
|
p_err("can't parse name");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
return prog_fd_by_nametag(name, fds, false);
|
|
|
|
} else if (is_prefix(**argv, "pinned")) {
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
path = **argv;
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
|
|
|
|
if ((*fds)[0] < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prog_parse_fd(int *argc, char ***argv)
|
|
|
|
{
|
|
|
|
int *fds = NULL;
|
|
|
|
int nb_fds, fd;
|
|
|
|
|
|
|
|
fds = malloc(sizeof(int));
|
|
|
|
if (!fds) {
|
|
|
|
p_err("mem alloc failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
nb_fds = prog_parse_fds(argc, argv, &fds);
|
|
|
|
if (nb_fds != 1) {
|
|
|
|
if (nb_fds > 1) {
|
|
|
|
p_err("several programs match this handle");
|
|
|
|
while (nb_fds--)
|
|
|
|
close(fds[nb_fds]);
|
|
|
|
}
|
|
|
|
fd = -1;
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = fds[0];
|
|
|
|
exit_free:
|
|
|
|
free(fds);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int map_fd_by_name(char *name, int **fds)
|
|
|
|
{
|
|
|
|
unsigned int id = 0;
|
|
|
|
int fd, nb_fds = 0;
|
|
|
|
void *tmp;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
|
|
|
|
err = bpf_map_get_next_id(id, &id);
|
|
|
|
if (err) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
p_err("%s", strerror(errno));
|
|
|
|
goto err_close_fds;
|
|
|
|
}
|
|
|
|
return nb_fds;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = bpf_map_get_fd_by_id(id);
|
|
|
|
if (fd < 0) {
|
|
|
|
p_err("can't get map by id (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
goto err_close_fds;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get map info (%u): %s",
|
|
|
|
id, strerror(errno));
|
|
|
|
goto err_close_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nb_fds > 0) {
|
|
|
|
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
|
|
|
|
if (!tmp) {
|
|
|
|
p_err("failed to realloc");
|
|
|
|
goto err_close_fd;
|
|
|
|
}
|
|
|
|
*fds = tmp;
|
|
|
|
}
|
|
|
|
(*fds)[nb_fds++] = fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
err_close_fd:
|
|
|
|
close(fd);
|
|
|
|
err_close_fds:
|
|
|
|
while (--nb_fds >= 0)
|
|
|
|
close((*fds)[nb_fds]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int map_parse_fds(int *argc, char ***argv, int **fds)
|
|
|
|
{
|
|
|
|
if (is_prefix(**argv, "id")) {
|
|
|
|
unsigned int id;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
id = strtoul(**argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
|
|
|
p_err("can't parse %s as ID", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
(*fds)[0] = bpf_map_get_fd_by_id(id);
|
|
|
|
if ((*fds)[0] < 0) {
|
|
|
|
p_err("get map by id (%u): %s", id, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
} else if (is_prefix(**argv, "name")) {
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
name = **argv;
|
|
|
|
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
|
|
|
|
p_err("can't parse name");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
return map_fd_by_name(name, fds);
|
|
|
|
} else if (is_prefix(**argv, "pinned")) {
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
path = **argv;
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
|
|
|
|
if ((*fds)[0] < 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int map_parse_fd(int *argc, char ***argv)
|
|
|
|
{
|
|
|
|
int *fds = NULL;
|
|
|
|
int nb_fds, fd;
|
|
|
|
|
|
|
|
fds = malloc(sizeof(int));
|
|
|
|
if (!fds) {
|
|
|
|
p_err("mem alloc failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
nb_fds = map_parse_fds(argc, argv, &fds);
|
|
|
|
if (nb_fds != 1) {
|
|
|
|
if (nb_fds > 1) {
|
|
|
|
p_err("several maps match this handle");
|
|
|
|
while (nb_fds--)
|
|
|
|
close(fds[nb_fds]);
|
|
|
|
}
|
|
|
|
fd = -1;
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = fds[0];
|
|
|
|
exit_free:
|
|
|
|
free(fds);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = map_parse_fd(argc, argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, info, info_len);
|
|
|
|
if (err) {
|
|
|
|
p_err("can't get map info: %s", strerror(errno));
|
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|