mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-21 00:39:07 +08:00
Compare commits
42 Commits
v1.2_netda
...
v1.2.2p_ne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
360a2fd909 | ||
|
|
05f94ddbb8 | ||
|
|
bf88aaa6fe | ||
|
|
f117080307 | ||
|
|
8b905090e8 | ||
|
|
6c020e6c47 | ||
|
|
1743bd1e40 | ||
|
|
a2258003f2 | ||
|
|
add1aac281 | ||
|
|
ea27ebcffd | ||
|
|
b9c4ad5468 | ||
|
|
732c4c6df2 | ||
|
|
6bec18258c | ||
|
|
3f33f9a6b8 | ||
|
|
ec6f716eda | ||
|
|
3c7fcfe0ce | ||
|
|
ef3e2ef82a | ||
|
|
45188d0d01 | ||
|
|
f02ec78083 | ||
|
|
fa1a18d38b | ||
|
|
ba7a44da68 | ||
|
|
cb23f981c3 | ||
|
|
f7eb43b90f | ||
|
|
9710829e78 | ||
|
|
e021ccbd7d | ||
|
|
0755b497cf | ||
|
|
c4ffdf1e72 | ||
|
|
c850306199 | ||
|
|
fb6998382d | ||
|
|
9aea1da2bb | ||
|
|
8b4e1b39a4 | ||
|
|
a50544ef45 | ||
|
|
bfb0454244 | ||
|
|
79811cad50 | ||
|
|
4bb0b0ca09 | ||
|
|
ac42790129 | ||
|
|
6a6cf6dcdc | ||
|
|
b9711e7015 | ||
|
|
4c484d662c | ||
|
|
1c9aa4791a | ||
|
|
3f591a6610 | ||
|
|
532293bdf4 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1 +1 @@
|
|||||||
assets/ export-ignore
|
assets/** export-ignore
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd ${REPO_ROOT}/${REPO_PATH}
|
cd ${REPO_ROOT}/${REPO_PATH}
|
||||||
|
make headers
|
||||||
make \
|
make \
|
||||||
CLANG=clang-${LLVM_VERSION} \
|
CLANG=clang-${LLVM_VERSION} \
|
||||||
LLC=llc-${LLVM_VERSION} \
|
LLC=llc-${LLVM_VERSION} \
|
||||||
|
|||||||
152953
.github/actions/build-selftests/vmlinux.h
vendored
152953
.github/actions/build-selftests/vmlinux.h
vendored
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
|||||||
71b547f561247897a0a14f3082730156c0533fed
|
496720b7cfb6574a8f6f4d434f23e3d1e6cfaeb9
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2ddade322925641ee2a75f13665c51f2e74d7791
|
a3e7e6b17946f48badce98d7ac360678a0ea7393
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
From ff8be5401b359e23ec2b74184034082564bac7c5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Daniel=20M=C3=BCller?= <deso@posteo.net>
|
||||||
|
Date: Thu, 25 May 2023 16:04:20 -0700
|
||||||
|
Subject: [PATCH] selftests/bpf: Check whether to run selftest
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
The sockopt test invokes test__start_subtest and then unconditionally
|
||||||
|
asserts the success. That means that even if deny-listed, any test will
|
||||||
|
still run and potentially fail.
|
||||||
|
Evaluate the return value of test__start_subtest() to achieve the
|
||||||
|
desired behavior, as other tests do.
|
||||||
|
|
||||||
|
Signed-off-by: Daniel Müller <deso@posteo.net>
|
||||||
|
---
|
||||||
|
tools/testing/selftests/bpf/prog_tests/sockopt.c | 4 +++-
|
||||||
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c
|
||||||
|
index 33dd45..9e6a5e 100644
|
||||||
|
--- a/tools/testing/selftests/bpf/prog_tests/sockopt.c
|
||||||
|
+++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c
|
||||||
|
@@ -1060,7 +1060,9 @@ void test_sockopt(void)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||||
|
- test__start_subtest(tests[i].descr);
|
||||||
|
+ if (!test__start_subtest(tests[i].descr))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
2.34.1
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
From d3484f640bc82cff459beb85a00f7ebab20f0a41 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
|
||||||
|
Date: Sun, 9 Apr 2023 11:28:31 +0900
|
||||||
|
Subject: [PATCH] tracing: fprobe: Initialize ret valiable to fix smatch error
|
||||||
|
|
||||||
|
The commit 39d954200bf6 ("fprobe: Skip exit_handler if entry_handler returns
|
||||||
|
!0") introduced a hidden dependency of 'ret' local variable in the
|
||||||
|
fprobe_handler(), Smatch warns the `ret` can be accessed without
|
||||||
|
initialization.
|
||||||
|
|
||||||
|
kernel/trace/fprobe.c:59 fprobe_handler()
|
||||||
|
error: uninitialized symbol 'ret'.
|
||||||
|
|
||||||
|
kernel/trace/fprobe.c
|
||||||
|
49 fpr->entry_ip = ip;
|
||||||
|
50 if (fp->entry_data_size)
|
||||||
|
51 entry_data = fpr->data;
|
||||||
|
52 }
|
||||||
|
53
|
||||||
|
54 if (fp->entry_handler)
|
||||||
|
55 ret = fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data);
|
||||||
|
|
||||||
|
ret is only initialized if there is an ->entry_handler
|
||||||
|
|
||||||
|
56
|
||||||
|
57 /* If entry_handler returns !0, nmissed is not counted. */
|
||||||
|
58 if (rh) {
|
||||||
|
|
||||||
|
rh is only true if there is an ->exit_handler. Presumably if you have
|
||||||
|
and ->exit_handler that means you also have a ->entry_handler but Smatch
|
||||||
|
is not smart enough to figure it out.
|
||||||
|
|
||||||
|
--> 59 if (ret)
|
||||||
|
^^^
|
||||||
|
Warning here.
|
||||||
|
|
||||||
|
60 rethook_recycle(rh);
|
||||||
|
61 else
|
||||||
|
62 rethook_hook(rh, ftrace_get_regs(fregs), true);
|
||||||
|
63 }
|
||||||
|
64 out:
|
||||||
|
65 ftrace_test_recursion_unlock(bit);
|
||||||
|
66 }
|
||||||
|
|
||||||
|
Reported-by: Dan Carpenter <error27@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/all/85429a5c-a4b9-499e-b6c0-cbd313291c49@kili.mountain
|
||||||
|
Fixes: 39d954200bf6 ("fprobe: Skip exit_handler if entry_handler returns !0")
|
||||||
|
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
|
||||||
|
---
|
||||||
|
kernel/trace/fprobe.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
|
||||||
|
index 9abb3905bc8e..293184227394 100644
|
||||||
|
--- a/kernel/trace/fprobe.c
|
||||||
|
+++ b/kernel/trace/fprobe.c
|
||||||
|
@@ -27,7 +27,7 @@ static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
|
||||||
|
struct rethook_node *rh = NULL;
|
||||||
|
struct fprobe *fp;
|
||||||
|
void *entry_data = NULL;
|
||||||
|
- int bit, ret;
|
||||||
|
+ int bit, ret = 0;
|
||||||
|
|
||||||
|
fp = container_of(ops, struct fprobe, ops);
|
||||||
|
if (fprobe_disabled(fp))
|
||||||
|
--
|
||||||
|
2.34.1
|
||||||
|
|
||||||
@@ -35,8 +35,6 @@ signal_pending
|
|||||||
skeleton
|
skeleton
|
||||||
sockmap_ktls
|
sockmap_ktls
|
||||||
sockopt
|
sockopt
|
||||||
sockopt_inherit
|
|
||||||
sockopt_multi
|
|
||||||
spinlock
|
spinlock
|
||||||
stacktrace_map
|
stacktrace_map
|
||||||
stacktrace_map_raw_tp
|
stacktrace_map_raw_tp
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ sock_fields # v5.10+
|
|||||||
socket_cookie # v5.12+
|
socket_cookie # v5.12+
|
||||||
sockmap_basic # uses new socket fields, 5.8+
|
sockmap_basic # uses new socket fields, 5.8+
|
||||||
sockmap_listen # no listen socket supportin SOCKMAP
|
sockmap_listen # no listen socket supportin SOCKMAP
|
||||||
|
sockopt/getsockopt: ignore >PAGE_SIZE optlen
|
||||||
|
sockopt/setsockopt: ignore >PAGE_SIZE optlen
|
||||||
sockopt_sk
|
sockopt_sk
|
||||||
sockopt_qos_to_cc # v5.15+
|
sockopt_qos_to_cc # v5.15+
|
||||||
stacktrace_build_id # v5.9+
|
stacktrace_build_id # v5.9+
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
decap_sanity # weird failure with decap_sanity_ns netns already existing, TBD
|
decap_sanity # weird failure with decap_sanity_ns netns already existing, TBD
|
||||||
|
bpf_nf/tc-bpf-ct # test consistently failing on x86: https://github.com/libbpf/libbpf/pull/698#issuecomment-1590341200
|
||||||
|
bpf_nf/xdp-ct # test consistently failing on x86: https://github.com/libbpf/libbpf/pull/698#issuecomment-1590341200
|
||||||
|
kprobe_multi_bench_attach # suspected to cause crashes in CI
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
# TEMPORARY
|
# TEMPORARY
|
||||||
|
sockmap_listen/sockhash VSOCK test_vsock_redir
|
||||||
usdt/basic # failing verifier due to bounds check after LLVM update
|
usdt/basic # failing verifier due to bounds check after LLVM update
|
||||||
usdt/multispec # same as above
|
usdt/multispec # same as above
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ read_lists() {
|
|||||||
if [[ -s "$path" ]]; then
|
if [[ -s "$path" ]]; then
|
||||||
cat "$path"
|
cat "$path"
|
||||||
fi;
|
fi;
|
||||||
done) | cut -d'#' -f1 | tr -s ' \t\n' ','
|
done) | cut -d'#' -f1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | tr -s '\n' ','
|
||||||
}
|
}
|
||||||
|
|
||||||
test_progs() {
|
test_progs() {
|
||||||
@@ -22,7 +22,7 @@ test_progs() {
|
|||||||
# "&& true" does not change the return code (it is not executed
|
# "&& true" does not change the return code (it is not executed
|
||||||
# if the Python script fails), but it prevents exiting on a
|
# if the Python script fails), but it prevents exiting on a
|
||||||
# failure due to the "set -e".
|
# failure due to the "set -e".
|
||||||
./test_progs ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
./test_progs ${DENYLIST:+-d"$DENYLIST"} ${ALLOWLIST:+-a"$ALLOWLIST"} && true
|
||||||
echo "test_progs:$?" >> "${STATUS_FILE}"
|
echo "test_progs:$?" >> "${STATUS_FILE}"
|
||||||
foldable end test_progs
|
foldable end test_progs
|
||||||
fi
|
fi
|
||||||
@@ -30,7 +30,7 @@ test_progs() {
|
|||||||
|
|
||||||
test_progs_no_alu32() {
|
test_progs_no_alu32() {
|
||||||
foldable start test_progs-no_alu32 "Testing test_progs-no_alu32"
|
foldable start test_progs-no_alu32 "Testing test_progs-no_alu32"
|
||||||
./test_progs-no_alu32 ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
./test_progs-no_alu32 ${DENYLIST:+-d"$DENYLIST"} ${ALLOWLIST:+-a"$ALLOWLIST"} && true
|
||||||
echo "test_progs-no_alu32:$?" >> "${STATUS_FILE}"
|
echo "test_progs-no_alu32:$?" >> "${STATUS_FILE}"
|
||||||
foldable end test_progs-no_alu32
|
foldable end test_progs-no_alu32
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,13 @@ test_verifier() {
|
|||||||
|
|
||||||
foldable end vm_init
|
foldable end vm_init
|
||||||
|
|
||||||
|
foldable start kernel_config "Kconfig"
|
||||||
|
|
||||||
|
zcat /proc/config.gz
|
||||||
|
|
||||||
|
foldable end kernel_config
|
||||||
|
|
||||||
|
|
||||||
configs_path=/${PROJECT_NAME}/selftests/bpf
|
configs_path=/${PROJECT_NAME}/selftests/bpf
|
||||||
local_configs_path=${PROJECT_NAME}/vmtest/configs
|
local_configs_path=${PROJECT_NAME}/vmtest/configs
|
||||||
DENYLIST=$(read_lists \
|
DENYLIST=$(read_lists \
|
||||||
|
|||||||
@@ -986,6 +986,7 @@ enum bpf_prog_type {
|
|||||||
BPF_PROG_TYPE_LSM,
|
BPF_PROG_TYPE_LSM,
|
||||||
BPF_PROG_TYPE_SK_LOOKUP,
|
BPF_PROG_TYPE_SK_LOOKUP,
|
||||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||||
|
BPF_PROG_TYPE_NETFILTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_attach_type {
|
enum bpf_attach_type {
|
||||||
@@ -1034,6 +1035,7 @@ enum bpf_attach_type {
|
|||||||
BPF_TRACE_KPROBE_MULTI,
|
BPF_TRACE_KPROBE_MULTI,
|
||||||
BPF_LSM_CGROUP,
|
BPF_LSM_CGROUP,
|
||||||
BPF_STRUCT_OPS,
|
BPF_STRUCT_OPS,
|
||||||
|
BPF_NETFILTER,
|
||||||
__MAX_BPF_ATTACH_TYPE
|
__MAX_BPF_ATTACH_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1050,6 +1052,7 @@ enum bpf_link_type {
|
|||||||
BPF_LINK_TYPE_PERF_EVENT = 7,
|
BPF_LINK_TYPE_PERF_EVENT = 7,
|
||||||
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
||||||
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
||||||
|
BPF_LINK_TYPE_NETFILTER = 10,
|
||||||
|
|
||||||
MAX_BPF_LINK_TYPE,
|
MAX_BPF_LINK_TYPE,
|
||||||
};
|
};
|
||||||
@@ -1270,6 +1273,9 @@ enum {
|
|||||||
|
|
||||||
/* Create a map that will be registered/unregesitered by the backed bpf_link */
|
/* Create a map that will be registered/unregesitered by the backed bpf_link */
|
||||||
BPF_F_LINK = (1U << 13),
|
BPF_F_LINK = (1U << 13),
|
||||||
|
|
||||||
|
/* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */
|
||||||
|
BPF_F_PATH_FD = (1U << 14),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags for BPF_PROG_QUERY. */
|
/* Flags for BPF_PROG_QUERY. */
|
||||||
@@ -1418,6 +1424,13 @@ union bpf_attr {
|
|||||||
__aligned_u64 pathname;
|
__aligned_u64 pathname;
|
||||||
__u32 bpf_fd;
|
__u32 bpf_fd;
|
||||||
__u32 file_flags;
|
__u32 file_flags;
|
||||||
|
/* Same as dirfd in openat() syscall; see openat(2)
|
||||||
|
* manpage for details of path FD and pathname semantics;
|
||||||
|
* path_fd should accompanied by BPF_F_PATH_FD flag set in
|
||||||
|
* file_flags field, otherwise it should be set to zero;
|
||||||
|
* if BPF_F_PATH_FD flag is not set, AT_FDCWD is assumed.
|
||||||
|
*/
|
||||||
|
__s32 path_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
|
struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
|
||||||
@@ -1560,6 +1573,12 @@ union bpf_attr {
|
|||||||
*/
|
*/
|
||||||
__u64 cookie;
|
__u64 cookie;
|
||||||
} tracing;
|
} tracing;
|
||||||
|
struct {
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
} netfilter;
|
||||||
};
|
};
|
||||||
} link_create;
|
} link_create;
|
||||||
|
|
||||||
@@ -3159,6 +3178,10 @@ union bpf_attr {
|
|||||||
* **BPF_FIB_LOOKUP_DIRECT**
|
* **BPF_FIB_LOOKUP_DIRECT**
|
||||||
* Do a direct table lookup vs full lookup using FIB
|
* Do a direct table lookup vs full lookup using FIB
|
||||||
* rules.
|
* rules.
|
||||||
|
* **BPF_FIB_LOOKUP_TBID**
|
||||||
|
* Used with BPF_FIB_LOOKUP_DIRECT.
|
||||||
|
* Use the routing table ID present in *params*->tbid
|
||||||
|
* for the fib lookup.
|
||||||
* **BPF_FIB_LOOKUP_OUTPUT**
|
* **BPF_FIB_LOOKUP_OUTPUT**
|
||||||
* Perform lookup from an egress perspective (default is
|
* Perform lookup from an egress perspective (default is
|
||||||
* ingress).
|
* ingress).
|
||||||
@@ -6410,6 +6433,12 @@ struct bpf_link_info {
|
|||||||
struct {
|
struct {
|
||||||
__u32 map_id;
|
__u32 map_id;
|
||||||
} struct_ops;
|
} struct_ops;
|
||||||
|
struct {
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
} netfilter;
|
||||||
};
|
};
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
@@ -6807,6 +6836,7 @@ enum {
|
|||||||
BPF_FIB_LOOKUP_DIRECT = (1U << 0),
|
BPF_FIB_LOOKUP_DIRECT = (1U << 0),
|
||||||
BPF_FIB_LOOKUP_OUTPUT = (1U << 1),
|
BPF_FIB_LOOKUP_OUTPUT = (1U << 1),
|
||||||
BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2),
|
BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2),
|
||||||
|
BPF_FIB_LOOKUP_TBID = (1U << 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -6867,9 +6897,19 @@ struct bpf_fib_lookup {
|
|||||||
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* output */
|
union {
|
||||||
__be16 h_vlan_proto;
|
struct {
|
||||||
__be16 h_vlan_TCI;
|
/* output */
|
||||||
|
__be16 h_vlan_proto;
|
||||||
|
__be16 h_vlan_TCI;
|
||||||
|
};
|
||||||
|
/* input: when accompanied with the
|
||||||
|
* 'BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID` flags, a
|
||||||
|
* specific routing table to use for the fib lookup.
|
||||||
|
*/
|
||||||
|
__u32 tbid;
|
||||||
|
};
|
||||||
|
|
||||||
__u8 smac[6]; /* ETH_ALEN */
|
__u8 smac[6]; /* ETH_ALEN */
|
||||||
__u8 dmac[6]; /* ETH_ALEN */
|
__u8 dmac[6]; /* ETH_ALEN */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ rm -rf elfutils
|
|||||||
git clone git://sourceware.org/git/elfutils.git
|
git clone git://sourceware.org/git/elfutils.git
|
||||||
(
|
(
|
||||||
cd elfutils
|
cd elfutils
|
||||||
git checkout e9f3045caa5c4498f371383e5519151942d48b6d
|
git checkout 67a187d4c1790058fc7fd218317851cb68bb087c
|
||||||
git log --oneline -1
|
git log --oneline -1
|
||||||
|
|
||||||
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
||||||
find -name Makefile.am | xargs sed -i 's/,--no-undefined//'
|
sed -i 's/^\(NO_UNDEFINED=\).*/\1/' configure.ac
|
||||||
|
|
||||||
# ASan isn't compatible with -Wl,-z,defs either:
|
# ASan isn't compatible with -Wl,-z,defs either:
|
||||||
# https://clang.llvm.org/docs/AddressSanitizer.html#usage
|
# https://clang.llvm.org/docs/AddressSanitizer.html#usage
|
||||||
@@ -62,6 +62,7 @@ fi
|
|||||||
|
|
||||||
autoreconf -i -f
|
autoreconf -i -f
|
||||||
if ! ./configure --enable-maintainer-mode --disable-debuginfod --disable-libdebuginfod \
|
if ! ./configure --enable-maintainer-mode --disable-debuginfod --disable-libdebuginfod \
|
||||||
|
--disable-demangler --without-bzlib --without-lzma --without-zstd \
|
||||||
CC="$CC" CFLAGS="-Wno-error $CFLAGS" CXX="$CXX" CXXFLAGS="-Wno-error $CXXFLAGS" LDFLAGS="$CFLAGS"; then
|
CC="$CC" CFLAGS="-Wno-error $CFLAGS" CXX="$CXX" CXXFLAGS="-Wno-error $CXXFLAGS" LDFLAGS="$CFLAGS"; then
|
||||||
cat config.log
|
cat config.log
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
LIBBPF_MAJOR_VERSION := 1
|
LIBBPF_MAJOR_VERSION := 1
|
||||||
LIBBPF_MINOR_VERSION := 2
|
LIBBPF_MINOR_VERSION := 3
|
||||||
LIBBPF_PATCH_VERSION := 0
|
LIBBPF_PATCH_VERSION := 0
|
||||||
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
||||||
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
||||||
|
|||||||
25
src/bpf.c
25
src/bpf.c
@@ -572,20 +572,30 @@ int bpf_map_update_batch(int fd, const void *keys, const void *values, __u32 *co
|
|||||||
(void *)keys, (void *)values, count, opts);
|
(void *)keys, (void *)values, count, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_obj_pin(int fd, const char *pathname)
|
int bpf_obj_pin_opts(int fd, const char *pathname, const struct bpf_obj_pin_opts *opts)
|
||||||
{
|
{
|
||||||
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
const size_t attr_sz = offsetofend(union bpf_attr, path_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, bpf_obj_pin_opts))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, attr_sz);
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.path_fd = OPTS_GET(opts, path_fd, 0);
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
|
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
||||||
attr.bpf_fd = fd;
|
attr.bpf_fd = fd;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_OBJ_PIN, &attr, attr_sz);
|
ret = sys_bpf(BPF_OBJ_PIN, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpf_obj_pin(int fd, const char *pathname)
|
||||||
|
{
|
||||||
|
return bpf_obj_pin_opts(fd, pathname, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_obj_get(const char *pathname)
|
int bpf_obj_get(const char *pathname)
|
||||||
{
|
{
|
||||||
return bpf_obj_get_opts(pathname, NULL);
|
return bpf_obj_get_opts(pathname, NULL);
|
||||||
@@ -593,7 +603,7 @@ int bpf_obj_get(const char *pathname)
|
|||||||
|
|
||||||
int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
||||||
{
|
{
|
||||||
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
const size_t attr_sz = offsetofend(union bpf_attr, path_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -601,6 +611,7 @@ int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
|||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, attr_sz);
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.path_fd = OPTS_GET(opts, path_fd, 0);
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
||||||
|
|
||||||
@@ -730,6 +741,14 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
if (!OPTS_ZEROED(opts, tracing))
|
if (!OPTS_ZEROED(opts, tracing))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
break;
|
break;
|
||||||
|
case BPF_NETFILTER:
|
||||||
|
attr.link_create.netfilter.pf = OPTS_GET(opts, netfilter.pf, 0);
|
||||||
|
attr.link_create.netfilter.hooknum = OPTS_GET(opts, netfilter.hooknum, 0);
|
||||||
|
attr.link_create.netfilter.priority = OPTS_GET(opts, netfilter.priority, 0);
|
||||||
|
attr.link_create.netfilter.flags = OPTS_GET(opts, netfilter.flags, 0);
|
||||||
|
if (!OPTS_ZEROED(opts, netfilter))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (!OPTS_ZEROED(opts, flags))
|
if (!OPTS_ZEROED(opts, flags))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|||||||
24
src/bpf.h
24
src/bpf.h
@@ -284,16 +284,30 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values
|
|||||||
__u32 *count,
|
__u32 *count,
|
||||||
const struct bpf_map_batch_opts *opts);
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_obj_pin_opts {
|
||||||
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
|
||||||
|
__u32 file_flags;
|
||||||
|
int path_fd;
|
||||||
|
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_obj_pin_opts__last_field path_fd
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
||||||
|
LIBBPF_API int bpf_obj_pin_opts(int fd, const char *pathname,
|
||||||
|
const struct bpf_obj_pin_opts *opts);
|
||||||
|
|
||||||
struct bpf_obj_get_opts {
|
struct bpf_obj_get_opts {
|
||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
|
||||||
__u32 file_flags;
|
__u32 file_flags;
|
||||||
|
int path_fd;
|
||||||
|
|
||||||
size_t :0;
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_obj_get_opts__last_field file_flags
|
#define bpf_obj_get_opts__last_field path_fd
|
||||||
|
|
||||||
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
|
||||||
LIBBPF_API int bpf_obj_get(const char *pathname);
|
LIBBPF_API int bpf_obj_get(const char *pathname);
|
||||||
LIBBPF_API int bpf_obj_get_opts(const char *pathname,
|
LIBBPF_API int bpf_obj_get_opts(const char *pathname,
|
||||||
const struct bpf_obj_get_opts *opts);
|
const struct bpf_obj_get_opts *opts);
|
||||||
@@ -335,6 +349,12 @@ struct bpf_link_create_opts {
|
|||||||
struct {
|
struct {
|
||||||
__u64 cookie;
|
__u64 cookie;
|
||||||
} tracing;
|
} tracing;
|
||||||
|
struct {
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
} netfilter;
|
||||||
};
|
};
|
||||||
size_t :0;
|
size_t :0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1832,6 +1832,10 @@ static long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *
|
|||||||
* **BPF_FIB_LOOKUP_DIRECT**
|
* **BPF_FIB_LOOKUP_DIRECT**
|
||||||
* Do a direct table lookup vs full lookup using FIB
|
* Do a direct table lookup vs full lookup using FIB
|
||||||
* rules.
|
* rules.
|
||||||
|
* **BPF_FIB_LOOKUP_TBID**
|
||||||
|
* Used with BPF_FIB_LOOKUP_DIRECT.
|
||||||
|
* Use the routing table ID present in *params*->tbid
|
||||||
|
* for the fib lookup.
|
||||||
* **BPF_FIB_LOOKUP_OUTPUT**
|
* **BPF_FIB_LOOKUP_OUTPUT**
|
||||||
* Perform lookup from an egress perspective (default is
|
* Perform lookup from an egress perspective (default is
|
||||||
* ingress).
|
* ingress).
|
||||||
|
|||||||
@@ -77,16 +77,21 @@
|
|||||||
/*
|
/*
|
||||||
* Helper macros to manipulate data structures
|
* Helper macros to manipulate data structures
|
||||||
*/
|
*/
|
||||||
#ifndef offsetof
|
|
||||||
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
/* offsetof() definition that uses __builtin_offset() might not preserve field
|
||||||
#endif
|
* offset CO-RE relocation properly, so force-redefine offsetof() using
|
||||||
#ifndef container_of
|
* old-school approach which works with CO-RE correctly
|
||||||
|
*/
|
||||||
|
#undef offsetof
|
||||||
|
#define offsetof(type, member) ((unsigned long)&((type *)0)->member)
|
||||||
|
|
||||||
|
/* redefined container_of() to ensure we use the above offsetof() macro */
|
||||||
|
#undef container_of
|
||||||
#define container_of(ptr, type, member) \
|
#define container_of(ptr, type, member) \
|
||||||
({ \
|
({ \
|
||||||
void *__mptr = (void *)(ptr); \
|
void *__mptr = (void *)(ptr); \
|
||||||
((type *)(__mptr - offsetof(type, member))); \
|
((type *)(__mptr - offsetof(type, member))); \
|
||||||
})
|
})
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compiler (optimization) barrier.
|
* Compiler (optimization) barrier.
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ struct pt_regs___arm64 {
|
|||||||
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions
|
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* riscv provides struct user_regs_struct instead of struct pt_regs to userspace */
|
||||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||||
#define __PT_PARM1_REG a0
|
#define __PT_PARM1_REG a0
|
||||||
#define __PT_PARM2_REG a1
|
#define __PT_PARM2_REG a1
|
||||||
@@ -383,7 +384,7 @@ struct pt_regs___arm64 {
|
|||||||
* https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf
|
* https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */
|
/* arc provides struct user_regs_struct instead of struct pt_regs to userspace */
|
||||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||||
#define __PT_PARM1_REG scratch.r0
|
#define __PT_PARM1_REG scratch.r0
|
||||||
#define __PT_PARM2_REG scratch.r1
|
#define __PT_PARM2_REG scratch.r1
|
||||||
|
|||||||
@@ -1064,7 +1064,7 @@ static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
long sz;
|
long sz;
|
||||||
|
|
||||||
f = fopen(path, "rb");
|
f = fopen(path, "rbe");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|||||||
@@ -2250,9 +2250,25 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
|
|||||||
const struct btf_type *t,
|
const struct btf_type *t,
|
||||||
__u32 id,
|
__u32 id,
|
||||||
const void *data,
|
const void *data,
|
||||||
__u8 bits_offset)
|
__u8 bits_offset,
|
||||||
|
__u8 bit_sz)
|
||||||
{
|
{
|
||||||
__s64 size = btf__resolve_size(d->btf, id);
|
__s64 size;
|
||||||
|
|
||||||
|
if (bit_sz) {
|
||||||
|
/* bits_offset is at most 7. bit_sz is at most 128. */
|
||||||
|
__u8 nr_bytes = (bits_offset + bit_sz + 7) / 8;
|
||||||
|
|
||||||
|
/* When bit_sz is non zero, it is called from
|
||||||
|
* btf_dump_struct_data() where it only cares about
|
||||||
|
* negative error value.
|
||||||
|
* Return nr_bytes in success case to make it
|
||||||
|
* consistent as the regular integer case below.
|
||||||
|
*/
|
||||||
|
return data + nr_bytes > d->typed_dump->data_end ? -E2BIG : nr_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = btf__resolve_size(d->btf, id);
|
||||||
|
|
||||||
if (size < 0 || size >= INT_MAX) {
|
if (size < 0 || size >= INT_MAX) {
|
||||||
pr_warn("unexpected size [%zu] for id [%u]\n",
|
pr_warn("unexpected size [%zu] for id [%u]\n",
|
||||||
@@ -2407,7 +2423,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
|
|||||||
{
|
{
|
||||||
int size, err = 0;
|
int size, err = 0;
|
||||||
|
|
||||||
size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset);
|
size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset, bit_sz);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return size;
|
return size;
|
||||||
err = btf_dump_type_data_check_zero(d, t, id, data, bits_offset, bit_sz);
|
err = btf_dump_type_data_check_zero(d, t, id, data, bits_offset, bit_sz);
|
||||||
|
|||||||
@@ -703,17 +703,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
|
|||||||
/* obtain fd in BPF_REG_9 */
|
/* obtain fd in BPF_REG_9 */
|
||||||
emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7));
|
emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7));
|
||||||
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
|
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
|
||||||
/* jump to fd_array store if fd denotes module BTF */
|
/* load fd_array slot pointer */
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
|
||||||
|
/* store BTF fd in slot, 0 for vmlinux */
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
|
||||||
|
/* jump to insn[insn_idx].off store if fd denotes module BTF */
|
||||||
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
|
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
|
||||||
/* set the default value for off */
|
/* set the default value for off */
|
||||||
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
|
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
|
||||||
/* skip BTF fd store for vmlinux BTF */
|
/* skip BTF fd store for vmlinux BTF */
|
||||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 4));
|
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
|
||||||
/* load fd_array slot pointer */
|
|
||||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
|
||||||
0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
|
|
||||||
/* store BTF fd in slot */
|
|
||||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
|
|
||||||
/* store index into insn[insn_idx].off */
|
/* store index into insn[insn_idx].off */
|
||||||
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx));
|
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx));
|
||||||
log:
|
log:
|
||||||
|
|||||||
@@ -80,16 +80,6 @@ struct hashmap {
|
|||||||
size_t sz;
|
size_t sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HASHMAP_INIT(hash_fn, equal_fn, ctx) { \
|
|
||||||
.hash_fn = (hash_fn), \
|
|
||||||
.equal_fn = (equal_fn), \
|
|
||||||
.ctx = (ctx), \
|
|
||||||
.buckets = NULL, \
|
|
||||||
.cap = 0, \
|
|
||||||
.cap_bits = 0, \
|
|
||||||
.sz = 0, \
|
|
||||||
}
|
|
||||||
|
|
||||||
void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
|
void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
|
||||||
hashmap_equal_fn equal_fn, void *ctx);
|
hashmap_equal_fn equal_fn, void *ctx);
|
||||||
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
||||||
|
|||||||
418
src/libbpf.c
418
src/libbpf.c
@@ -117,6 +117,7 @@ static const char * const attach_type_name[] = {
|
|||||||
[BPF_PERF_EVENT] = "perf_event",
|
[BPF_PERF_EVENT] = "perf_event",
|
||||||
[BPF_TRACE_KPROBE_MULTI] = "trace_kprobe_multi",
|
[BPF_TRACE_KPROBE_MULTI] = "trace_kprobe_multi",
|
||||||
[BPF_STRUCT_OPS] = "struct_ops",
|
[BPF_STRUCT_OPS] = "struct_ops",
|
||||||
|
[BPF_NETFILTER] = "netfilter",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const link_type_name[] = {
|
static const char * const link_type_name[] = {
|
||||||
@@ -130,6 +131,7 @@ static const char * const link_type_name[] = {
|
|||||||
[BPF_LINK_TYPE_PERF_EVENT] = "perf_event",
|
[BPF_LINK_TYPE_PERF_EVENT] = "perf_event",
|
||||||
[BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi",
|
[BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi",
|
||||||
[BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops",
|
[BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops",
|
||||||
|
[BPF_LINK_TYPE_NETFILTER] = "netfilter",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const map_type_name[] = {
|
static const char * const map_type_name[] = {
|
||||||
@@ -201,6 +203,7 @@ static const char * const prog_type_name[] = {
|
|||||||
[BPF_PROG_TYPE_LSM] = "lsm",
|
[BPF_PROG_TYPE_LSM] = "lsm",
|
||||||
[BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
|
[BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
|
||||||
[BPF_PROG_TYPE_SYSCALL] = "syscall",
|
[BPF_PROG_TYPE_SYSCALL] = "syscall",
|
||||||
|
[BPF_PROG_TYPE_NETFILTER] = "netfilter",
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __base_pr(enum libbpf_print_level level, const char *format,
|
static int __base_pr(enum libbpf_print_level level, const char *format,
|
||||||
@@ -1359,7 +1362,7 @@ static int bpf_object__elf_init(struct bpf_object *obj)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Elf is corrupted/truncated, avoid calling elf_strptr. */
|
/* ELF is corrupted/truncated, avoid calling elf_strptr. */
|
||||||
if (!elf_rawdata(elf_getscn(elf, obj->efile.shstrndx), NULL)) {
|
if (!elf_rawdata(elf_getscn(elf, obj->efile.shstrndx), NULL)) {
|
||||||
pr_warn("elf: failed to get section names strings from %s: %s\n",
|
pr_warn("elf: failed to get section names strings from %s: %s\n",
|
||||||
obj->path, elf_errmsg(-1));
|
obj->path, elf_errmsg(-1));
|
||||||
@@ -1498,16 +1501,36 @@ static struct bpf_map *bpf_object__add_map(struct bpf_object *obj)
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t bpf_map_mmap_sz(const struct bpf_map *map)
|
static size_t bpf_map_mmap_sz(unsigned int value_sz, unsigned int max_entries)
|
||||||
{
|
{
|
||||||
long page_sz = sysconf(_SC_PAGE_SIZE);
|
const long page_sz = sysconf(_SC_PAGE_SIZE);
|
||||||
size_t map_sz;
|
size_t map_sz;
|
||||||
|
|
||||||
map_sz = (size_t)roundup(map->def.value_size, 8) * map->def.max_entries;
|
map_sz = (size_t)roundup(value_sz, 8) * max_entries;
|
||||||
map_sz = roundup(map_sz, page_sz);
|
map_sz = roundup(map_sz, page_sz);
|
||||||
return map_sz;
|
return map_sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpf_map_mmap_resize(struct bpf_map *map, size_t old_sz, size_t new_sz)
|
||||||
|
{
|
||||||
|
void *mmaped;
|
||||||
|
|
||||||
|
if (!map->mmaped)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (old_sz == new_sz)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mmaped = mmap(NULL, new_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (mmaped == MAP_FAILED)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
memcpy(mmaped, map->mmaped, min(old_sz, new_sz));
|
||||||
|
munmap(map->mmaped, old_sz);
|
||||||
|
map->mmaped = mmaped;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char *internal_map_name(struct bpf_object *obj, const char *real_name)
|
static char *internal_map_name(struct bpf_object *obj, const char *real_name)
|
||||||
{
|
{
|
||||||
char map_name[BPF_OBJ_NAME_LEN], *p;
|
char map_name[BPF_OBJ_NAME_LEN], *p;
|
||||||
@@ -1606,6 +1629,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
|
|||||||
{
|
{
|
||||||
struct bpf_map_def *def;
|
struct bpf_map_def *def;
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
|
size_t mmap_sz;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
map = bpf_object__add_map(obj);
|
map = bpf_object__add_map(obj);
|
||||||
@@ -1640,7 +1664,8 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
|
|||||||
pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
|
pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n",
|
||||||
map->name, map->sec_idx, map->sec_offset, def->map_flags);
|
map->name, map->sec_idx, map->sec_offset, def->map_flags);
|
||||||
|
|
||||||
map->mmaped = mmap(NULL, bpf_map_mmap_sz(map), PROT_READ | PROT_WRITE,
|
mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries);
|
||||||
|
map->mmaped = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
if (map->mmaped == MAP_FAILED) {
|
if (map->mmaped == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
@@ -4327,7 +4352,7 @@ static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info)
|
|||||||
snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd);
|
snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd);
|
||||||
memset(info, 0, sizeof(*info));
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "re");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("failed to open %s: %d. No procfs support?\n", file,
|
pr_warn("failed to open %s: %d. No procfs support?\n", file,
|
||||||
@@ -4390,18 +4415,17 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
|
|||||||
if (!new_name)
|
if (!new_name)
|
||||||
return libbpf_err(-errno);
|
return libbpf_err(-errno);
|
||||||
|
|
||||||
new_fd = open("/", O_RDONLY | O_CLOEXEC);
|
/*
|
||||||
|
* Like dup(), but make sure new FD is >= 3 and has O_CLOEXEC set.
|
||||||
|
* This is similar to what we do in ensure_good_fd(), but without
|
||||||
|
* closing original FD.
|
||||||
|
*/
|
||||||
|
new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||||
if (new_fd < 0) {
|
if (new_fd < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto err_free_new_name;
|
goto err_free_new_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_fd = dup3(fd, new_fd, O_CLOEXEC);
|
|
||||||
if (new_fd < 0) {
|
|
||||||
err = -errno;
|
|
||||||
goto err_close_new_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = zclose(map->fd);
|
err = zclose(map->fd);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
@@ -5447,6 +5471,10 @@ static int load_module_btfs(struct bpf_object *obj)
|
|||||||
err = bpf_btf_get_next_id(id, &id);
|
err = bpf_btf_get_next_id(id, &id);
|
||||||
if (err && errno == ENOENT)
|
if (err && errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (err && errno == EPERM) {
|
||||||
|
pr_debug("skipping module BTFs loading, missing privileges\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("failed to iterate BTF objects: %d\n", err);
|
pr_warn("failed to iterate BTF objects: %d\n", err);
|
||||||
@@ -6133,7 +6161,11 @@ static int append_subprog_relos(struct bpf_program *main_prog, struct bpf_progra
|
|||||||
if (main_prog == subprog)
|
if (main_prog == subprog)
|
||||||
return 0;
|
return 0;
|
||||||
relos = libbpf_reallocarray(main_prog->reloc_desc, new_cnt, sizeof(*relos));
|
relos = libbpf_reallocarray(main_prog->reloc_desc, new_cnt, sizeof(*relos));
|
||||||
if (!relos)
|
/* if new count is zero, reallocarray can return a valid NULL result;
|
||||||
|
* in this case the previous pointer will be freed, so we *have to*
|
||||||
|
* reassign old pointer to the new value (even if it's NULL)
|
||||||
|
*/
|
||||||
|
if (!relos && new_cnt)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (subprog->nr_reloc)
|
if (subprog->nr_reloc)
|
||||||
memcpy(relos + main_prog->nr_reloc, subprog->reloc_desc,
|
memcpy(relos + main_prog->nr_reloc, subprog->reloc_desc,
|
||||||
@@ -7431,7 +7463,7 @@ int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *ctx)
|
|||||||
int ret, err = 0;
|
int ret, err = 0;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
f = fopen("/proc/kallsyms", "r");
|
f = fopen("/proc/kallsyms", "re");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("failed to open /proc/kallsyms: %d\n", err);
|
pr_warn("failed to open /proc/kallsyms: %d\n", err);
|
||||||
@@ -8292,7 +8324,10 @@ static void bpf_map__destroy(struct bpf_map *map)
|
|||||||
map->init_slots_sz = 0;
|
map->init_slots_sz = 0;
|
||||||
|
|
||||||
if (map->mmaped) {
|
if (map->mmaped) {
|
||||||
munmap(map->mmaped, bpf_map_mmap_sz(map));
|
size_t mmap_sz;
|
||||||
|
|
||||||
|
mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries);
|
||||||
|
munmap(map->mmaped, mmap_sz);
|
||||||
map->mmaped = NULL;
|
map->mmaped = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8501,7 +8536,8 @@ int bpf_program__set_insns(struct bpf_program *prog,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
insns = libbpf_reallocarray(prog->insns, new_insn_cnt, sizeof(*insns));
|
insns = libbpf_reallocarray(prog->insns, new_insn_cnt, sizeof(*insns));
|
||||||
if (!insns) {
|
/* NULL is a valid return from reallocarray if the new count is zero */
|
||||||
|
if (!insns && new_insn_cnt) {
|
||||||
pr_warn("prog '%s': failed to realloc prog code\n", prog->name);
|
pr_warn("prog '%s': failed to realloc prog code\n", prog->name);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -8531,13 +8567,31 @@ enum bpf_prog_type bpf_program__type(const struct bpf_program *prog)
|
|||||||
return prog->type;
|
return prog->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t custom_sec_def_cnt;
|
||||||
|
static struct bpf_sec_def *custom_sec_defs;
|
||||||
|
static struct bpf_sec_def custom_fallback_def;
|
||||||
|
static bool has_custom_fallback_def;
|
||||||
|
static int last_custom_sec_def_handler_id;
|
||||||
|
|
||||||
int bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type)
|
int bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type)
|
||||||
{
|
{
|
||||||
if (prog->obj->loaded)
|
if (prog->obj->loaded)
|
||||||
return libbpf_err(-EBUSY);
|
return libbpf_err(-EBUSY);
|
||||||
|
|
||||||
|
/* if type is not changed, do nothing */
|
||||||
|
if (prog->type == type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
prog->type = type;
|
prog->type = type;
|
||||||
prog->sec_def = NULL;
|
|
||||||
|
/* If a program type was changed, we need to reset associated SEC()
|
||||||
|
* handler, as it will be invalid now. The only exception is a generic
|
||||||
|
* fallback handler, which by definition is program type-agnostic and
|
||||||
|
* is a catch-all custom handler, optionally set by the application,
|
||||||
|
* so should be able to handle any type of BPF program.
|
||||||
|
*/
|
||||||
|
if (prog->sec_def != &custom_fallback_def)
|
||||||
|
prog->sec_def = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8710,15 +8764,9 @@ static const struct bpf_sec_def section_defs[] = {
|
|||||||
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
|
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
|
||||||
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
|
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
|
||||||
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
|
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
|
||||||
|
SEC_DEF("netfilter", NETFILTER, BPF_NETFILTER, SEC_NONE),
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t custom_sec_def_cnt;
|
|
||||||
static struct bpf_sec_def *custom_sec_defs;
|
|
||||||
static struct bpf_sec_def custom_fallback_def;
|
|
||||||
static bool has_custom_fallback_def;
|
|
||||||
|
|
||||||
static int last_custom_sec_def_handler_id;
|
|
||||||
|
|
||||||
int libbpf_register_prog_handler(const char *sec,
|
int libbpf_register_prog_handler(const char *sec,
|
||||||
enum bpf_prog_type prog_type,
|
enum bpf_prog_type prog_type,
|
||||||
enum bpf_attach_type exp_attach_type,
|
enum bpf_attach_type exp_attach_type,
|
||||||
@@ -8798,7 +8846,11 @@ int libbpf_unregister_prog_handler(int handler_id)
|
|||||||
|
|
||||||
/* try to shrink the array, but it's ok if we couldn't */
|
/* try to shrink the array, but it's ok if we couldn't */
|
||||||
sec_defs = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt, sizeof(*sec_defs));
|
sec_defs = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt, sizeof(*sec_defs));
|
||||||
if (sec_defs)
|
/* if new count is zero, reallocarray can return a valid NULL result;
|
||||||
|
* in this case the previous pointer will be freed, so we *have to*
|
||||||
|
* reassign old pointer to the new value (even if it's NULL)
|
||||||
|
*/
|
||||||
|
if (sec_defs || custom_sec_def_cnt == 0)
|
||||||
custom_sec_defs = sec_defs;
|
custom_sec_defs = sec_defs;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -9409,10 +9461,103 @@ __u32 bpf_map__value_size(const struct bpf_map *map)
|
|||||||
return map->def.value_size;
|
return map->def.value_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int map_btf_datasec_resize(struct bpf_map *map, __u32 size)
|
||||||
|
{
|
||||||
|
struct btf *btf;
|
||||||
|
struct btf_type *datasec_type, *var_type;
|
||||||
|
struct btf_var_secinfo *var;
|
||||||
|
const struct btf_type *array_type;
|
||||||
|
const struct btf_array *array;
|
||||||
|
int vlen, element_sz, new_array_id;
|
||||||
|
__u32 nr_elements;
|
||||||
|
|
||||||
|
/* check btf existence */
|
||||||
|
btf = bpf_object__btf(map->obj);
|
||||||
|
if (!btf)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/* verify map is datasec */
|
||||||
|
datasec_type = btf_type_by_id(btf, bpf_map__btf_value_type_id(map));
|
||||||
|
if (!btf_is_datasec(datasec_type)) {
|
||||||
|
pr_warn("map '%s': cannot be resized, map value type is not a datasec\n",
|
||||||
|
bpf_map__name(map));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify datasec has at least one var */
|
||||||
|
vlen = btf_vlen(datasec_type);
|
||||||
|
if (vlen == 0) {
|
||||||
|
pr_warn("map '%s': cannot be resized, map value datasec is empty\n",
|
||||||
|
bpf_map__name(map));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify last var in the datasec is an array */
|
||||||
|
var = &btf_var_secinfos(datasec_type)[vlen - 1];
|
||||||
|
var_type = btf_type_by_id(btf, var->type);
|
||||||
|
array_type = skip_mods_and_typedefs(btf, var_type->type, NULL);
|
||||||
|
if (!btf_is_array(array_type)) {
|
||||||
|
pr_warn("map '%s': cannot be resized, last var must be an array\n",
|
||||||
|
bpf_map__name(map));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify request size aligns with array */
|
||||||
|
array = btf_array(array_type);
|
||||||
|
element_sz = btf__resolve_size(btf, array->type);
|
||||||
|
if (element_sz <= 0 || (size - var->offset) % element_sz != 0) {
|
||||||
|
pr_warn("map '%s': cannot be resized, element size (%d) doesn't align with new total size (%u)\n",
|
||||||
|
bpf_map__name(map), element_sz, size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new array based on the existing array, but with new length */
|
||||||
|
nr_elements = (size - var->offset) / element_sz;
|
||||||
|
new_array_id = btf__add_array(btf, array->index_type, array->type, nr_elements);
|
||||||
|
if (new_array_id < 0)
|
||||||
|
return new_array_id;
|
||||||
|
|
||||||
|
/* adding a new btf type invalidates existing pointers to btf objects,
|
||||||
|
* so refresh pointers before proceeding
|
||||||
|
*/
|
||||||
|
datasec_type = btf_type_by_id(btf, map->btf_value_type_id);
|
||||||
|
var = &btf_var_secinfos(datasec_type)[vlen - 1];
|
||||||
|
var_type = btf_type_by_id(btf, var->type);
|
||||||
|
|
||||||
|
/* finally update btf info */
|
||||||
|
datasec_type->size = size;
|
||||||
|
var->size = size - var->offset;
|
||||||
|
var_type->type = new_array_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
|
int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
|
||||||
{
|
{
|
||||||
if (map->fd >= 0)
|
if (map->fd >= 0)
|
||||||
return libbpf_err(-EBUSY);
|
return libbpf_err(-EBUSY);
|
||||||
|
|
||||||
|
if (map->mmaped) {
|
||||||
|
int err;
|
||||||
|
size_t mmap_old_sz, mmap_new_sz;
|
||||||
|
|
||||||
|
mmap_old_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries);
|
||||||
|
mmap_new_sz = bpf_map_mmap_sz(size, map->def.max_entries);
|
||||||
|
err = bpf_map_mmap_resize(map, mmap_old_sz, mmap_new_sz);
|
||||||
|
if (err) {
|
||||||
|
pr_warn("map '%s': failed to resize memory-mapped region: %d\n",
|
||||||
|
bpf_map__name(map), err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = map_btf_datasec_resize(map, size);
|
||||||
|
if (err && err != -ENOENT) {
|
||||||
|
pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %d\n",
|
||||||
|
bpf_map__name(map), err);
|
||||||
|
map->btf_value_type_id = 0;
|
||||||
|
map->btf_key_type_id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
map->def.value_size = size;
|
map->def.value_size = size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -9438,7 +9583,7 @@ int bpf_map__set_initial_value(struct bpf_map *map,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize)
|
void *bpf_map__initial_value(struct bpf_map *map, size_t *psize)
|
||||||
{
|
{
|
||||||
if (!map->mmaped)
|
if (!map->mmaped)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -9954,7 +10099,7 @@ static int parse_uint_from_file(const char *file, const char *fmt)
|
|||||||
int err, ret;
|
int err, ret;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
f = fopen(file, "r");
|
f = fopen(file, "re");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_debug("failed to open '%s': %s\n", file,
|
pr_debug("failed to open '%s': %s\n", file,
|
||||||
@@ -10103,6 +10248,18 @@ static const char *tracefs_uprobe_events(void)
|
|||||||
return use_debugfs() ? DEBUGFS"/uprobe_events" : TRACEFS"/uprobe_events";
|
return use_debugfs() ? DEBUGFS"/uprobe_events" : TRACEFS"/uprobe_events";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *tracefs_available_filter_functions(void)
|
||||||
|
{
|
||||||
|
return use_debugfs() ? DEBUGFS"/available_filter_functions"
|
||||||
|
: TRACEFS"/available_filter_functions";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *tracefs_available_filter_functions_addrs(void)
|
||||||
|
{
|
||||||
|
return use_debugfs() ? DEBUGFS"/available_filter_functions_addrs"
|
||||||
|
: TRACEFS"/available_filter_functions_addrs";
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_kprobe_legacy_event_name(char *buf, size_t buf_sz,
|
static void gen_kprobe_legacy_event_name(char *buf, size_t buf_sz,
|
||||||
const char *kfunc_name, size_t offset)
|
const char *kfunc_name, size_t offset)
|
||||||
{
|
{
|
||||||
@@ -10418,25 +10575,158 @@ struct kprobe_multi_resolve {
|
|||||||
size_t cnt;
|
size_t cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
struct avail_kallsyms_data {
|
||||||
resolve_kprobe_multi_cb(unsigned long long sym_addr, char sym_type,
|
char **syms;
|
||||||
const char *sym_name, void *ctx)
|
size_t cnt;
|
||||||
|
struct kprobe_multi_resolve *res;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int avail_func_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
struct kprobe_multi_resolve *res = ctx;
|
return strcmp(*(const char **)a, *(const char **)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avail_kallsyms_cb(unsigned long long sym_addr, char sym_type,
|
||||||
|
const char *sym_name, void *ctx)
|
||||||
|
{
|
||||||
|
struct avail_kallsyms_data *data = ctx;
|
||||||
|
struct kprobe_multi_resolve *res = data->res;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!glob_match(sym_name, res->pattern))
|
if (!bsearch(&sym_name, data->syms, data->cnt, sizeof(*data->syms), avail_func_cmp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = libbpf_ensure_mem((void **) &res->addrs, &res->cap, sizeof(unsigned long),
|
err = libbpf_ensure_mem((void **)&res->addrs, &res->cap, sizeof(*res->addrs), res->cnt + 1);
|
||||||
res->cnt + 1);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
res->addrs[res->cnt++] = (unsigned long) sym_addr;
|
res->addrs[res->cnt++] = (unsigned long)sym_addr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res)
|
||||||
|
{
|
||||||
|
const char *available_functions_file = tracefs_available_filter_functions();
|
||||||
|
struct avail_kallsyms_data data;
|
||||||
|
char sym_name[500];
|
||||||
|
FILE *f;
|
||||||
|
int err = 0, ret, i;
|
||||||
|
char **syms = NULL;
|
||||||
|
size_t cap = 0, cnt = 0;
|
||||||
|
|
||||||
|
f = fopen(available_functions_file, "re");
|
||||||
|
if (!f) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("failed to open %s: %d\n", available_functions_file, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
ret = fscanf(f, "%499s%*[^\n]\n", sym_name);
|
||||||
|
if (ret == EOF && feof(f))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
pr_warn("failed to parse available_filter_functions entry: %d\n", ret);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glob_match(sym_name, res->pattern))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = libbpf_ensure_mem((void **)&syms, &cap, sizeof(*syms), cnt + 1);
|
||||||
|
if (err)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
name = strdup(sym_name);
|
||||||
|
if (!name) {
|
||||||
|
err = -errno;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
syms[cnt++] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no entries found, bail out */
|
||||||
|
if (cnt == 0) {
|
||||||
|
err = -ENOENT;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort available functions */
|
||||||
|
qsort(syms, cnt, sizeof(*syms), avail_func_cmp);
|
||||||
|
|
||||||
|
data.syms = syms;
|
||||||
|
data.res = res;
|
||||||
|
data.cnt = cnt;
|
||||||
|
libbpf_kallsyms_parse(avail_kallsyms_cb, &data);
|
||||||
|
|
||||||
|
if (res->cnt == 0)
|
||||||
|
err = -ENOENT;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
for (i = 0; i < cnt; i++)
|
||||||
|
free((char *)syms[i]);
|
||||||
|
free(syms);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_available_filter_functions_addrs(void)
|
||||||
|
{
|
||||||
|
return access(tracefs_available_filter_functions_addrs(), R_OK) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res)
|
||||||
|
{
|
||||||
|
const char *available_path = tracefs_available_filter_functions_addrs();
|
||||||
|
char sym_name[500];
|
||||||
|
FILE *f;
|
||||||
|
int ret, err = 0;
|
||||||
|
unsigned long long sym_addr;
|
||||||
|
|
||||||
|
f = fopen(available_path, "re");
|
||||||
|
if (!f) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("failed to open %s: %d\n", available_path, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
ret = fscanf(f, "%llx %499s%*[^\n]\n", &sym_addr, sym_name);
|
||||||
|
if (ret == EOF && feof(f))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret != 2) {
|
||||||
|
pr_warn("failed to parse available_filter_functions_addrs entry: %d\n",
|
||||||
|
ret);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glob_match(sym_name, res->pattern))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = libbpf_ensure_mem((void **)&res->addrs, &res->cap,
|
||||||
|
sizeof(*res->addrs), res->cnt + 1);
|
||||||
|
if (err)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
res->addrs[res->cnt++] = (unsigned long)sym_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->cnt == 0)
|
||||||
|
err = -ENOENT;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
struct bpf_link *
|
struct bpf_link *
|
||||||
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
||||||
const char *pattern,
|
const char *pattern,
|
||||||
@@ -10473,13 +10763,12 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
|||||||
return libbpf_err_ptr(-EINVAL);
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
err = libbpf_kallsyms_parse(resolve_kprobe_multi_cb, &res);
|
if (has_available_filter_functions_addrs())
|
||||||
|
err = libbpf_available_kprobes_parse(&res);
|
||||||
|
else
|
||||||
|
err = libbpf_available_kallsyms_parse(&res);
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
if (!res.cnt) {
|
|
||||||
err = -ENOENT;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
addrs = res.addrs;
|
addrs = res.addrs;
|
||||||
cnt = res.cnt;
|
cnt = res.cnt;
|
||||||
}
|
}
|
||||||
@@ -11690,6 +11979,48 @@ static int attach_iter(const struct bpf_program *prog, long cookie, struct bpf_l
|
|||||||
return libbpf_get_error(*link);
|
return libbpf_get_error(*link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bpf_link *bpf_program__attach_netfilter(const struct bpf_program *prog,
|
||||||
|
const struct bpf_netfilter_opts *opts)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_link_create_opts, lopts);
|
||||||
|
struct bpf_link *link;
|
||||||
|
int prog_fd, link_fd;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, bpf_netfilter_opts))
|
||||||
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
|
||||||
|
prog_fd = bpf_program__fd(prog);
|
||||||
|
if (prog_fd < 0) {
|
||||||
|
pr_warn("prog '%s': can't attach before loaded\n", prog->name);
|
||||||
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
link = calloc(1, sizeof(*link));
|
||||||
|
if (!link)
|
||||||
|
return libbpf_err_ptr(-ENOMEM);
|
||||||
|
|
||||||
|
link->detach = &bpf_link__detach_fd;
|
||||||
|
|
||||||
|
lopts.netfilter.pf = OPTS_GET(opts, pf, 0);
|
||||||
|
lopts.netfilter.hooknum = OPTS_GET(opts, hooknum, 0);
|
||||||
|
lopts.netfilter.priority = OPTS_GET(opts, priority, 0);
|
||||||
|
lopts.netfilter.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
|
link_fd = bpf_link_create(prog_fd, 0, BPF_NETFILTER, &lopts);
|
||||||
|
if (link_fd < 0) {
|
||||||
|
char errmsg[STRERR_BUFSIZE];
|
||||||
|
|
||||||
|
link_fd = -errno;
|
||||||
|
free(link);
|
||||||
|
pr_warn("prog '%s': failed to attach to netfilter: %s\n",
|
||||||
|
prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
|
||||||
|
return libbpf_err_ptr(link_fd);
|
||||||
|
}
|
||||||
|
link->fd = link_fd;
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
struct bpf_link *bpf_program__attach(const struct bpf_program *prog)
|
struct bpf_link *bpf_program__attach(const struct bpf_program *prog)
|
||||||
{
|
{
|
||||||
struct bpf_link *link = NULL;
|
struct bpf_link *link = NULL;
|
||||||
@@ -12690,7 +13021,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
|
|||||||
|
|
||||||
for (i = 0; i < s->map_cnt; i++) {
|
for (i = 0; i < s->map_cnt; i++) {
|
||||||
struct bpf_map *map = *s->maps[i].map;
|
struct bpf_map *map = *s->maps[i].map;
|
||||||
size_t mmap_sz = bpf_map_mmap_sz(map);
|
size_t mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries);
|
||||||
int prot, map_fd = bpf_map__fd(map);
|
int prot, map_fd = bpf_map__fd(map);
|
||||||
void **mmaped = s->maps[i].mmaped;
|
void **mmaped = s->maps[i].mmaped;
|
||||||
|
|
||||||
@@ -12717,8 +13048,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s)
|
|||||||
* as per normal clean up procedure, so we don't need to worry
|
* as per normal clean up procedure, so we don't need to worry
|
||||||
* about it from skeleton's clean up perspective.
|
* about it from skeleton's clean up perspective.
|
||||||
*/
|
*/
|
||||||
*mmaped = mmap(map->mmaped, mmap_sz, prot,
|
*mmaped = mmap(map->mmaped, mmap_sz, prot, MAP_SHARED | MAP_FIXED, map_fd, 0);
|
||||||
MAP_SHARED | MAP_FIXED, map_fd, 0);
|
|
||||||
if (*mmaped == MAP_FAILED) {
|
if (*mmaped == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
*mmaped = NULL;
|
*mmaped = NULL;
|
||||||
|
|||||||
33
src/libbpf.h
33
src/libbpf.h
@@ -718,6 +718,21 @@ LIBBPF_API struct bpf_link *
|
|||||||
bpf_program__attach_freplace(const struct bpf_program *prog,
|
bpf_program__attach_freplace(const struct bpf_program *prog,
|
||||||
int target_fd, const char *attach_func_name);
|
int target_fd, const char *attach_func_name);
|
||||||
|
|
||||||
|
struct bpf_netfilter_opts {
|
||||||
|
/* size of this struct, for forward/backward compatibility */
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
};
|
||||||
|
#define bpf_netfilter_opts__last_field flags
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_netfilter(const struct bpf_program *prog,
|
||||||
|
const struct bpf_netfilter_opts *opts);
|
||||||
|
|
||||||
struct bpf_map;
|
struct bpf_map;
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
||||||
@@ -869,8 +884,22 @@ LIBBPF_API int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node);
|
|||||||
/* get/set map key size */
|
/* get/set map key size */
|
||||||
LIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map);
|
LIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map);
|
||||||
LIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size);
|
LIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size);
|
||||||
/* get/set map value size */
|
/* get map value size */
|
||||||
LIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map);
|
LIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map);
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__set_value_size()** sets map value size.
|
||||||
|
* @param map the BPF map instance
|
||||||
|
* @return 0, on success; negative error, otherwise
|
||||||
|
*
|
||||||
|
* There is a special case for maps with associated memory-mapped regions, like
|
||||||
|
* the global data section maps (bss, data, rodata). When this function is used
|
||||||
|
* on such a map, the mapped region is resized. Afterward, an attempt is made to
|
||||||
|
* adjust the corresponding BTF info. This attempt is best-effort and can only
|
||||||
|
* succeed if the last variable of the data section map is an array. The array
|
||||||
|
* BTF type is replaced by a new BTF array type with a different length.
|
||||||
|
* Any previously existing pointers returned from bpf_map__initial_value() or
|
||||||
|
* corresponding data section skeleton pointer must be reinitialized.
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size);
|
LIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size);
|
||||||
/* get map key/value BTF type IDs */
|
/* get map key/value BTF type IDs */
|
||||||
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
|
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
|
||||||
@@ -884,7 +913,7 @@ LIBBPF_API int bpf_map__set_map_extra(struct bpf_map *map, __u64 map_extra);
|
|||||||
|
|
||||||
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
||||||
const void *data, size_t size);
|
const void *data, size_t size);
|
||||||
LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);
|
LIBBPF_API void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief **bpf_map__is_internal()** tells the caller whether or not the
|
* @brief **bpf_map__is_internal()** tells the caller whether or not the
|
||||||
|
|||||||
@@ -391,3 +391,9 @@ LIBBPF_1.2.0 {
|
|||||||
bpf_map_get_info_by_fd;
|
bpf_map_get_info_by_fd;
|
||||||
bpf_prog_get_info_by_fd;
|
bpf_prog_get_info_by_fd;
|
||||||
} LIBBPF_1.1.0;
|
} LIBBPF_1.1.0;
|
||||||
|
|
||||||
|
LIBBPF_1.3.0 {
|
||||||
|
global:
|
||||||
|
bpf_obj_pin_opts;
|
||||||
|
bpf_program__attach_netfilter;
|
||||||
|
} LIBBPF_1.2.0;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ static __u32 get_ubuntu_kernel_version(void)
|
|||||||
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)
|
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
f = fopen(ubuntu_kver_file, "r");
|
f = fopen(ubuntu_kver_file, "re");
|
||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -181,6 +181,9 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
|
|||||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||||
break;
|
break;
|
||||||
|
case BPF_PROG_TYPE_NETFILTER:
|
||||||
|
opts.expected_attach_type = BPF_NETFILTER;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
#define __LIBBPF_VERSION_H
|
#define __LIBBPF_VERSION_H
|
||||||
|
|
||||||
#define LIBBPF_MAJOR_VERSION 1
|
#define LIBBPF_MAJOR_VERSION 1
|
||||||
#define LIBBPF_MINOR_VERSION 2
|
#define LIBBPF_MINOR_VERSION 3
|
||||||
|
|
||||||
#endif /* __LIBBPF_VERSION_H */
|
#endif /* __LIBBPF_VERSION_H */
|
||||||
|
|||||||
12
src/usdt.c
12
src/usdt.c
@@ -466,7 +466,7 @@ static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs,
|
|||||||
|
|
||||||
proceed:
|
proceed:
|
||||||
sprintf(line, "/proc/%d/maps", pid);
|
sprintf(line, "/proc/%d/maps", pid);
|
||||||
f = fopen(line, "r");
|
f = fopen(line, "re");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("usdt: failed to open '%s' to get base addr of '%s': %d\n",
|
pr_warn("usdt: failed to open '%s' to get base addr of '%s': %d\n",
|
||||||
@@ -771,7 +771,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
|
|||||||
target->rel_ip = usdt_rel_ip;
|
target->rel_ip = usdt_rel_ip;
|
||||||
target->sema_off = usdt_sema_off;
|
target->sema_off = usdt_sema_off;
|
||||||
|
|
||||||
/* notes.args references strings from Elf itself, so they can
|
/* notes.args references strings from ELF itself, so they can
|
||||||
* be referenced safely until elf_end() call
|
* be referenced safely until elf_end() call
|
||||||
*/
|
*/
|
||||||
target->spec_str = note.args;
|
target->spec_str = note.args;
|
||||||
@@ -852,8 +852,11 @@ static int bpf_link_usdt_detach(struct bpf_link *link)
|
|||||||
* system is so exhausted on memory, it's the least of user's
|
* system is so exhausted on memory, it's the least of user's
|
||||||
* concerns, probably.
|
* concerns, probably.
|
||||||
* So just do our best here to return those IDs to usdt_manager.
|
* So just do our best here to return those IDs to usdt_manager.
|
||||||
|
* Another edge case when we can legitimately get NULL is when
|
||||||
|
* new_cnt is zero, which can happen in some edge cases, so we
|
||||||
|
* need to be careful about that.
|
||||||
*/
|
*/
|
||||||
if (new_free_ids) {
|
if (new_free_ids || new_cnt == 0) {
|
||||||
memcpy(new_free_ids + man->free_spec_cnt, usdt_link->spec_ids,
|
memcpy(new_free_ids + man->free_spec_cnt, usdt_link->spec_ids,
|
||||||
usdt_link->spec_cnt * sizeof(*usdt_link->spec_ids));
|
usdt_link->spec_cnt * sizeof(*usdt_link->spec_ids));
|
||||||
man->free_spec_ids = new_free_ids;
|
man->free_spec_ids = new_free_ids;
|
||||||
@@ -954,8 +957,7 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
|||||||
spec_map_fd = bpf_map__fd(man->specs_map);
|
spec_map_fd = bpf_map__fd(man->specs_map);
|
||||||
ip_map_fd = bpf_map__fd(man->ip_to_spec_id_map);
|
ip_map_fd = bpf_map__fd(man->ip_to_spec_id_map);
|
||||||
|
|
||||||
/* TODO: perform path resolution similar to uprobe's */
|
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||||
fd = open(path, O_RDONLY);
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("usdt: failed to open ELF binary '%s': %d\n", path, err);
|
pr_warn("usdt: failed to open ELF binary '%s': %d\n", path, err);
|
||||||
|
|||||||
Reference in New Issue
Block a user