mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-15 22:09:06 +08:00
Compare commits
1 Commits
netdata_pa
...
v1.2.1.p_n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82e09953ad |
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,3 +0,0 @@
|
||||
Thank you for considering a contribution!
|
||||
|
||||
Please note that the `libbpf` authoritative source code is developed as part of bpf-next Linux source tree under tools/lib/bpf subdirectory and is periodically synced to Github. As such, all the libbpf changes should be sent to BPF mailing list, please don't open PRs here unless you are changing Github-specific parts of libbpf (e.g., Github-specific Makefile).
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
printf "all:\n\ttouch bpf_test_no_cfi.ko\n\nclean:\n" > bpf_test_no_cfi/Makefile
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
printf "all:\n\ttouch bpf_test_no_cfi.ko\n\nclean:\n" > bpf_test_no_cfi/Makefile
|
||||
|
||||
|
||||
171708
.github/actions/build-selftests/vmlinux.h
vendored
171708
.github/actions/build-selftests/vmlinux.h
vendored
File diff suppressed because it is too large
Load Diff
19
.github/actions/vmtest/action.yml
vendored
19
.github/actions/vmtest/action.yml
vendored
@@ -16,28 +16,11 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Allow CI user to access /dev/kvm (via qemu) w/o group change/relogin
|
||||
# by changing permissions set by udev.
|
||||
- name: Set /dev/kvm permissions
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -e /dev/kvm ]; then
|
||||
echo "/dev/kvm exists"
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
|
||||
| sudo tee /etc/udev/rules.d/99-kvm4all.rules > /dev/null
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
fi
|
||||
else
|
||||
echo "/dev/kvm does not exist"
|
||||
fi
|
||||
# setup environment
|
||||
- name: Setup environment
|
||||
uses: libbpf/ci/setup-build-env@main
|
||||
with:
|
||||
pahole: ${{ inputs.pahole }}
|
||||
arch: ${{ inputs.arch }}
|
||||
# 1. download CHECKPOINT kernel source
|
||||
- name: Get checkpoint commit
|
||||
shell: bash
|
||||
@@ -63,8 +46,6 @@ runs:
|
||||
cd .kernel
|
||||
cat tools/testing/selftests/bpf/config \
|
||||
tools/testing/selftests/bpf/config.${{ inputs.arch }} > .config
|
||||
# this file might or mihgt not exist depending on kernel version
|
||||
cat tools/testing/selftests/bpf/config.vm >> .config || :
|
||||
make olddefconfig && make prepare
|
||||
cd -
|
||||
foldable end
|
||||
|
||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: gcc-12
|
||||
target: RUN_GCC12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
@@ -63,14 +63,14 @@ jobs:
|
||||
- arch: s390x
|
||||
- arch: x86
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Pre-Setup
|
||||
- run: source /tmp/ci_setup && sudo -E $CI_ROOT/managers/ubuntu.sh
|
||||
if: matrix.arch == 'x86'
|
||||
name: Setup
|
||||
- uses: uraimo/run-on-arch-action@v2.7.1
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Build in docker
|
||||
if: matrix.arch != 'x86'
|
||||
with:
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
|
||||
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
name: Coverity
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- name: Run coverity
|
||||
run: |
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
env:
|
||||
|
||||
2
.github/workflows/ondemand.yml
vendored
2
.github/workflows/ondemand.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: vmtest with customized pahole/Kernel
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
with:
|
||||
|
||||
2
.github/workflows/pahole.yml
vendored
2
.github/workflows/pahole.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
env:
|
||||
STAGING: tmp.master
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
with:
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
runs_on: s390x
|
||||
arch: 's390x'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: "ubuntu-22.04"
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
builder: html
|
||||
@@ -22,5 +17,6 @@ formats:
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: docs/sphinx/requirements.txt
|
||||
- requirements: docs/sphinx/requirements.txt
|
||||
@@ -1 +1 @@
|
||||
443574b033876c85a35de4c65c14f7fe092222b2
|
||||
496720b7cfb6574a8f6f4d434f23e3d1e6cfaeb9
|
||||
|
||||
@@ -1 +1 @@
|
||||
14bb1e8c8d4ad5d9d2febb7d19c70a3cf536e1e5
|
||||
c628747cc8800cf6d33d09f7f42c8b6f91e64dc7
|
||||
|
||||
@@ -146,7 +146,7 @@ Distributions packaging libbpf from this mirror:
|
||||
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
||||
- [Arch](https://archlinux.org/packages/core/x86_64/libbpf/)
|
||||
- [Ubuntu](https://packages.ubuntu.com/source/jammy/libbpf)
|
||||
- [Ubuntu](https://packages.ubuntu.com/source/impish/libbpf)
|
||||
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
||||
|
||||
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
From 6fba14e2ed9d159f76b23fa5c16f3ea99acbc003 Mon Sep 17 00:00:00 2001
|
||||
From: Masahiro Yamada <masahiroy@kernel.org>
|
||||
Date: Thu, 5 Jan 2023 12:13:06 +0900
|
||||
Subject: [PATCH] s390: define RUNTIME_DISCARD_EXIT to fix link error with GNU
|
||||
ld < 2.36
|
||||
|
||||
Nathan Chancellor reports that the s390 vmlinux fails to link with
|
||||
GNU ld < 2.36 since commit 99cb0d917ffa ("arch: fix broken BuildID
|
||||
for arm64 and riscv").
|
||||
|
||||
It happens for defconfig, or more specifically for CONFIG_EXPOLINE=y.
|
||||
|
||||
$ s390x-linux-gnu-ld --version | head -n1
|
||||
GNU ld (GNU Binutils for Debian) 2.35.2
|
||||
$ make -s ARCH=s390 CROSS_COMPILE=s390x-linux-gnu- allnoconfig
|
||||
$ ./scripts/config -e CONFIG_EXPOLINE
|
||||
$ make -s ARCH=s390 CROSS_COMPILE=s390x-linux-gnu- olddefconfig
|
||||
$ make -s ARCH=s390 CROSS_COMPILE=s390x-linux-gnu-
|
||||
`.exit.text' referenced in section `.s390_return_reg' of drivers/base/dd.o: defined in discarded section `.exit.text' of drivers/base/dd.o
|
||||
make[1]: *** [scripts/Makefile.vmlinux:34: vmlinux] Error 1
|
||||
make: *** [Makefile:1252: vmlinux] Error 2
|
||||
|
||||
arch/s390/kernel/vmlinux.lds.S wants to keep EXIT_TEXT:
|
||||
|
||||
.exit.text : {
|
||||
EXIT_TEXT
|
||||
}
|
||||
|
||||
But, at the same time, EXIT_TEXT is thrown away by DISCARD because
|
||||
s390 does not define RUNTIME_DISCARD_EXIT.
|
||||
|
||||
I still do not understand why the latter wins after 99cb0d917ffa,
|
||||
but defining RUNTIME_DISCARD_EXIT seems correct because the comment
|
||||
line in arch/s390/kernel/vmlinux.lds.S says:
|
||||
|
||||
/*
|
||||
* .exit.text is discarded at runtime, not link time,
|
||||
* to deal with references from __bug_table
|
||||
*/
|
||||
|
||||
Nathan also found that binutils commit 21401fc7bf67 ("Duplicate output
|
||||
sections in scripts") cured this issue, so we cannot reproduce it with
|
||||
binutils 2.36+, but it is better to not rely on it.
|
||||
|
||||
Fixes: 99cb0d917ffa ("arch: fix broken BuildID for arm64 and riscv")
|
||||
Link: https://lore.kernel.org/all/Y7Jal56f6UBh1abE@dev-arch.thelio-3990X/
|
||||
Reported-by: Nathan Chancellor <nathan@kernel.org>
|
||||
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230105031306.1455409-1-masahiroy@kernel.org
|
||||
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
|
||||
---
|
||||
arch/s390/kernel/vmlinux.lds.S | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
|
||||
index 5ea3830af0cc..6e101e6f499d 100644
|
||||
--- a/arch/s390/kernel/vmlinux.lds.S
|
||||
+++ b/arch/s390/kernel/vmlinux.lds.S
|
||||
@@ -17,6 +17,8 @@
|
||||
/* Handle ro_after_init data on our own. */
|
||||
#define RO_AFTER_INIT_DATA
|
||||
|
||||
+#define RUNTIME_DISCARD_EXIT
|
||||
+
|
||||
#define EMITS_PT_NOTE
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
--
|
||||
2.30.2
|
||||
|
||||
@@ -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,46 @@
|
||||
From a8dfde09c90109e3a98af54847e91bde7dc2d5c2 Mon Sep 17 00:00:00 2001
|
||||
From: Song Liu <song@kernel.org>
|
||||
Date: Tue, 13 Dec 2022 14:05:00 -0800
|
||||
Subject: [PATCH] selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
BPF selftests require CONFIG_FUNCTION_ERROR_INJECTION to work. However,
|
||||
CONFIG_FUNCTION_ERROR_INJECTION is no longer 'y' by default after recent
|
||||
changes. As a result, we are seeing errors like the following from BPF CI:
|
||||
|
||||
bpf_testmod_test_read() is not modifiable
|
||||
__x64_sys_setdomainname is not sleepable
|
||||
__x64_sys_getpgid is not sleepable
|
||||
|
||||
Fix this by explicitly selecting CONFIG_FUNCTION_ERROR_INJECTION in the
|
||||
selftest config.
|
||||
|
||||
Fixes: a4412fdd49dc ("error-injection: Add prompt for function error injection")
|
||||
Reported-by: Daniel Müller <deso@posteo.net>
|
||||
Signed-off-by: Song Liu <song@kernel.org>
|
||||
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
|
||||
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Acked-by: Daniel Müller <deso@posteo.net>
|
||||
Link: https://lore.kernel.org/bpf/20221213220500.3427947-1-song@kernel.org
|
||||
Signed-off-by: Daniel Müller <deso@posteo.net>
|
||||
---
|
||||
tools/testing/selftests/bpf/config | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
|
||||
index 612f69..63cd4a 100644
|
||||
--- a/tools/testing/selftests/bpf/config
|
||||
+++ b/tools/testing/selftests/bpf/config
|
||||
@@ -16,6 +16,7 @@ CONFIG_CRYPTO_USER_API_HASH=y
|
||||
CONFIG_DYNAMIC_FTRACE=y
|
||||
CONFIG_FPROBE=y
|
||||
CONFIG_FTRACE_SYSCALLS=y
|
||||
+CONFIG_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_FUNCTION_TRACER=y
|
||||
CONFIG_GENEVE=y
|
||||
CONFIG_IKCONFIG=y
|
||||
--
|
||||
2.30.2
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
From 8267fc71abb2dc47338570e56dd3473a58313fce Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Mon, 17 Apr 2023 23:53:22 +0200
|
||||
Subject: [PATCH] veth: take into account peer device for
|
||||
NETDEV_XDP_ACT_NDO_XMIT xdp_features flag
|
||||
|
||||
For veth pairs, NETDEV_XDP_ACT_NDO_XMIT is supported by the current
|
||||
device if the peer one is running a XDP program or if it has GRO enabled.
|
||||
Fix the xdp_features flags reporting considering peer device and not
|
||||
current one for NETDEV_XDP_ACT_NDO_XMIT.
|
||||
|
||||
Fixes: fccca038f300 ("veth: take into account device reconfiguration for xdp_features flag")
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Link: https://lore.kernel.org/r/4f1ca6f6f6b42ae125bfdb5c7782217c83968b2e.1681767806.git.lorenzo@kernel.org
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
drivers/net/veth.c | 17 +++++++++++------
|
||||
1 file changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
|
||||
index e1b38fbf1dd9..4b3c6647edc6 100644
|
||||
--- a/drivers/net/veth.c
|
||||
+++ b/drivers/net/veth.c
|
||||
@@ -1262,11 +1262,12 @@ static void veth_set_xdp_features(struct net_device *dev)
|
||||
|
||||
peer = rtnl_dereference(priv->peer);
|
||||
if (peer && peer->real_num_tx_queues <= dev->real_num_rx_queues) {
|
||||
+ struct veth_priv *priv_peer = netdev_priv(peer);
|
||||
xdp_features_t val = NETDEV_XDP_ACT_BASIC |
|
||||
NETDEV_XDP_ACT_REDIRECT |
|
||||
NETDEV_XDP_ACT_RX_SG;
|
||||
|
||||
- if (priv->_xdp_prog || veth_gro_requested(dev))
|
||||
+ if (priv_peer->_xdp_prog || veth_gro_requested(peer))
|
||||
val |= NETDEV_XDP_ACT_NDO_XMIT |
|
||||
NETDEV_XDP_ACT_NDO_XMIT_SG;
|
||||
xdp_set_features_flag(dev, val);
|
||||
@@ -1504,19 +1505,23 @@ static int veth_set_features(struct net_device *dev,
|
||||
{
|
||||
netdev_features_t changed = features ^ dev->features;
|
||||
struct veth_priv *priv = netdev_priv(dev);
|
||||
+ struct net_device *peer;
|
||||
int err;
|
||||
|
||||
if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog)
|
||||
return 0;
|
||||
|
||||
+ peer = rtnl_dereference(priv->peer);
|
||||
if (features & NETIF_F_GRO) {
|
||||
err = veth_napi_enable(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- xdp_features_set_redirect_target(dev, true);
|
||||
+ if (peer)
|
||||
+ xdp_features_set_redirect_target(peer, true);
|
||||
} else {
|
||||
- xdp_features_clear_redirect_target(dev);
|
||||
+ if (peer)
|
||||
+ xdp_features_clear_redirect_target(peer);
|
||||
veth_napi_del(dev);
|
||||
}
|
||||
return 0;
|
||||
@@ -1598,13 +1603,13 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
|
||||
peer->max_mtu = max_mtu;
|
||||
}
|
||||
|
||||
- xdp_features_set_redirect_target(dev, true);
|
||||
+ xdp_features_set_redirect_target(peer, true);
|
||||
}
|
||||
|
||||
if (old_prog) {
|
||||
if (!prog) {
|
||||
- if (!veth_gro_requested(dev))
|
||||
- xdp_features_clear_redirect_target(dev);
|
||||
+ if (peer && !veth_gro_requested(dev))
|
||||
+ xdp_features_clear_redirect_target(peer);
|
||||
|
||||
if (dev->flags & IFF_UP)
|
||||
veth_disable_xdp(dev);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
From f267f262815033452195f46c43b572159262f533 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Date: Tue, 5 Mar 2024 10:08:28 +0100
|
||||
Subject: [PATCH 2/2] xdp, bonding: Fix feature flags when there are no slave
|
||||
devs anymore
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Commit 9b0ed890ac2a ("bonding: do not report NETDEV_XDP_ACT_XSK_ZEROCOPY")
|
||||
changed the driver from reporting everything as supported before a device
|
||||
was bonded into having the driver report that no XDP feature is supported
|
||||
until a real device is bonded as it seems to be more truthful given
|
||||
eventually real underlying devices decide what XDP features are supported.
|
||||
|
||||
The change however did not take into account when all slave devices get
|
||||
removed from the bond device. In this case after 9b0ed890ac2a, the driver
|
||||
keeps reporting a feature mask of 0x77, that is, NETDEV_XDP_ACT_MASK &
|
||||
~NETDEV_XDP_ACT_XSK_ZEROCOPY whereas it should have reported a feature
|
||||
mask of 0.
|
||||
|
||||
Fix it by resetting XDP feature flags in the same way as if no XDP program
|
||||
is attached to the bond device. This was uncovered by the XDP bond selftest
|
||||
which let BPF CI fail. After adjusting the starting masks on the latter
|
||||
to 0 instead of NETDEV_XDP_ACT_MASK the test passes again together with
|
||||
this fix.
|
||||
|
||||
Fixes: 9b0ed890ac2a ("bonding: do not report NETDEV_XDP_ACT_XSK_ZEROCOPY")
|
||||
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Cc: Magnus Karlsson <magnus.karlsson@intel.com>
|
||||
Cc: Prashant Batra <prbatra.mail@gmail.com>
|
||||
Cc: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Cc: Jakub Kicinski <kuba@kernel.org>
|
||||
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Message-ID: <20240305090829.17131-1-daniel@iogearbox.net>
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
drivers/net/bonding/bond_main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
||||
index a11748b8d69b..cd0683bcca03 100644
|
||||
--- a/drivers/net/bonding/bond_main.c
|
||||
+++ b/drivers/net/bonding/bond_main.c
|
||||
@@ -1811,7 +1811,7 @@ void bond_xdp_set_features(struct net_device *bond_dev)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
- if (!bond_xdp_check(bond)) {
|
||||
+ if (!bond_xdp_check(bond) || !bond_has_slaves(bond)) {
|
||||
xdp_clear_features_flag(bond_dev);
|
||||
return;
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -32,7 +32,9 @@ raw_tp_writable_test_run
|
||||
rdonly_maps
|
||||
section_names
|
||||
signal_pending
|
||||
skeleton
|
||||
sockmap_ktls
|
||||
sockopt
|
||||
spinlock
|
||||
stacktrace_map
|
||||
stacktrace_map_raw_tp
|
||||
@@ -42,7 +44,6 @@ task_fd_query_tp
|
||||
tc_bpf
|
||||
tcp_estats
|
||||
tcp_rtt
|
||||
test_global_funcs/arg_tag_ctx*
|
||||
tp_attach_query
|
||||
usdt/urand_pid_attach
|
||||
xdp
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# TEMPORARY
|
||||
btf_dump/btf_dump: syntax
|
||||
kprobe_multi_bench_attach
|
||||
core_reloc/enum64val
|
||||
core_reloc/size___diff_sz
|
||||
core_reloc/type_based___diff_sz
|
||||
test_ima # All of CI is broken on it following 6.3-rc1 merge
|
||||
|
||||
lwt_reroute # crashes kernel after netnext merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy"
|
||||
tc_links_ingress # started failing after net-next merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy"
|
||||
xdp_bonding/xdp_bonding_features # started failing after net merge from 359e54a93ab4 "l2tp: pass correct message length to ip6_append_data"
|
||||
tc_redirect/tc_redirect_dtime # uapi breakage after net-next commit 885c36e59f46 ("net: Re-use and set mono_delivery_time bit for userspace tstamp packets")
|
||||
migrate_reuseport/IPv4 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation
|
||||
migrate_reuseport/IPv6 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation
|
||||
@@ -1,5 +1,120 @@
|
||||
# This complements ALLOWLIST-5.5.0 but excludes subtest that can't work on 5.5
|
||||
# This file is not used and is there for historic purposes only.
|
||||
# See ALLOWLIST-5.5.0 instead.
|
||||
|
||||
# PERMANENTLY DISABLED
|
||||
align # verifier output format changed
|
||||
atomics # new atomic operations (v5.12+)
|
||||
atomic_bounds # new atomic operations (v5.12+)
|
||||
bind_perm # changed semantics of return values (v5.12+)
|
||||
bpf_cookie # 5.15+
|
||||
bpf_iter # bpf_iter support is missing
|
||||
bpf_obj_id # bpf_link support missing for GET_OBJ_INFO, GET_FD_BY_ID, etc
|
||||
bpf_tcp_ca # STRUCT_OPS is missing
|
||||
btf_map_in_map # inner map leak fixed in 5.8
|
||||
btf_skc_cls_ingress # v5.10+ functionality
|
||||
cg_storage_multi # v5.9+ functionality
|
||||
cgroup_attach_multi # BPF_F_REPLACE_PROG missing
|
||||
cgroup_link # LINK_CREATE is missing
|
||||
cgroup_skb_sk_lookup # bpf_sk_lookup_tcp() helper is missing
|
||||
check_mtu # missing BPF helper (v5.12+)
|
||||
cls_redirect # bpf_csum_level() helper is missing
|
||||
connect_force_port # cgroup/get{peer,sock}name{4,6} support is missing
|
||||
d_path # v5.10+ feature
|
||||
enable_stats # BPF_ENABLE_STATS support is missing
|
||||
fentry_fexit # bpf_prog_test_tracing missing
|
||||
fentry_test # bpf_prog_test_tracing missing
|
||||
fexit_bpf2bpf # freplace is missing
|
||||
fexit_sleep # relies on bpf_trampoline fix in 5.12+
|
||||
fexit_test # bpf_prog_test_tracing missing
|
||||
flow_dissector # bpf_link-based flow dissector is in 5.8+
|
||||
flow_dissector_reattach
|
||||
for_each # v5.12+
|
||||
get_func_ip_test # v5.15+
|
||||
get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
|
||||
hash_large_key # v5.11+
|
||||
ima # v5.11+
|
||||
kfree_skb # 32-bit pointer arith in test_pkt_access
|
||||
ksyms # __start_BTF has different name
|
||||
kfunc_call # v5.13+
|
||||
link_pinning # bpf_link is missing
|
||||
linked_vars # v5.13+
|
||||
load_bytes_relative # new functionality in 5.8
|
||||
lookup_and_delete # v5.14+
|
||||
map_init # per-CPU LRU missing
|
||||
map_ptr # test uses BPF_MAP_TYPE_RINGBUF, added in 5.8
|
||||
metadata # v5.10+
|
||||
migrate_reuseport # v5.14+
|
||||
mmap # 5.5 kernel is too permissive with re-mmaping
|
||||
modify_return # fmod_ret support is missing
|
||||
module_attach # module BTF support missing (v5.11+)
|
||||
netcnt
|
||||
netns_cookie # v5.15+
|
||||
ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
|
||||
pe_preserve_elems # v5.10+
|
||||
perf_branches # bpf_read_branch_records() helper is missing
|
||||
perf_link # v5.15+
|
||||
pkt_access # 32-bit pointer arith in test_pkt_access
|
||||
probe_read_user_str # kernel bug with garbage bytes at the end
|
||||
prog_run_xattr # 32-bit pointer arith in test_pkt_access
|
||||
raw_tp_test_run # v5.10+
|
||||
recursion # v5.12+
|
||||
ringbuf # BPF_MAP_TYPE_RINGBUF is supported in 5.8+
|
||||
|
||||
# bug in verifier w/ tracking references
|
||||
#reference_tracking/classifier/sk_lookup_success
|
||||
reference_tracking
|
||||
|
||||
select_reuseport # UDP support is missing
|
||||
send_signal # bpf_send_signal_thread() helper is missing
|
||||
sk_assign # bpf_sk_assign helper missing
|
||||
sk_lookup # v5.9+
|
||||
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
||||
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
||||
skb_helpers # helpers added in 5.8+
|
||||
skeleton # creates too big ARRAY map
|
||||
snprintf # v5.13+
|
||||
snprintf_btf # v5.10+
|
||||
sock_fields # v5.10+
|
||||
socket_cookie # v5.12+
|
||||
sockmap_basic # uses new socket fields, 5.8+
|
||||
sockmap_listen # no listen socket supportin SOCKMAP
|
||||
sockopt/getsockopt: ignore >PAGE_SIZE optlen
|
||||
sockopt/setsockopt: ignore >PAGE_SIZE optlen
|
||||
sockopt_sk
|
||||
sockopt_qos_to_cc # v5.15+
|
||||
stacktrace_build_id # v5.9+
|
||||
stack_var_off # v5.12+
|
||||
syscall # v5.14+
|
||||
task_local_storage # v5.12+
|
||||
task_pt_regs # v5.15+
|
||||
tcp_hdr_options # v5.10+, new TCP header options feature in BPF
|
||||
tcpbpf_user # LINK_CREATE is missing
|
||||
tc_redirect # v5.14+
|
||||
test_bpffs # v5.10+, new CONFIG_BPF_PRELOAD=y and CONFIG_BPF_PRELOAD_UMG=y|m
|
||||
test_bprm_opts # v5.11+
|
||||
test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
|
||||
test_local_storage # v5.10+ feature
|
||||
test_lsm # no BPF_LSM support
|
||||
test_overhead # no fmod_ret support
|
||||
test_profiler # needs verifier logic improvements from v5.10+
|
||||
test_skb_pkt_end # v5.11+
|
||||
timer # v5.15+
|
||||
timer_mim # v5.15+
|
||||
trace_ext # v5.10+
|
||||
trace_printk # v5.14+
|
||||
trampoline_count # v5.12+ have lower allowed limits
|
||||
udp_limit # no cgroup/sock_release BPF program type (5.9+)
|
||||
varlen # verifier bug fixed in later kernels
|
||||
vmlinux # hrtimer_nanosleep() signature changed incompatibly
|
||||
xdp_adjust_tail # new XDP functionality added in 5.8
|
||||
xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
|
||||
xdp_bonding # v5.15+
|
||||
xdp_bpf2bpf # freplace is missing
|
||||
xdp_context_test_run # v5.15+
|
||||
xdp_cpumap_attach # v5.9+
|
||||
xdp_devmap_attach # new feature in 5.8
|
||||
xdp_link # v5.9+
|
||||
|
||||
# SUBTESTS FAILING (block entire test until blocking subtests works properly)
|
||||
btf # "size check test", "func (Non zero vlen)"
|
||||
tailcalls # tailcall_bpf2bpf_1, tailcall_bpf2bpf_2, tailcall_bpf2bpf_3
|
||||
tc_bpf/tc_bpf_non_root
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
decap_sanity # weird failure with decap_sanity_ns netns already existing, TBD
|
||||
empty_skb # waiting the fix in bpf tree to make it to bpf-next
|
||||
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
|
||||
find_vma # test consistently fails on latest kernel, see https://github.com/libbpf/libbpf/issues/754 for details
|
||||
bpf_cookie/perf_event
|
||||
send_signal/send_signal_nmi
|
||||
send_signal/send_signal_nmi_thread
|
||||
|
||||
lwt_reroute # crashes kernel, fix pending upstream
|
||||
tc_links_ingress # fails, same fix is pending upstream
|
||||
tc_redirect # enough is enough, banned for life for flakiness
|
||||
|
||||
@@ -2,16 +2,3 @@
|
||||
sockmap_listen/sockhash VSOCK test_vsock_redir
|
||||
usdt/basic # failing verifier due to bounds check after LLVM update
|
||||
usdt/multispec # same as above
|
||||
|
||||
deny_namespace # not yet in bpf denylist
|
||||
tc_redirect/tc_redirect_dtime # very flaky
|
||||
lru_bug # not yet in bpf-next denylist
|
||||
|
||||
# Disabled temporarily for a crash.
|
||||
# https://lore.kernel.org/bpf/c9923c1d-971d-4022-8dc8-1364e929d34c@gmail.com/
|
||||
dummy_st_ops/dummy_init_ptr_arg
|
||||
fexit_bpf2bpf
|
||||
tailcalls
|
||||
trace_ext
|
||||
xdp_bpf2bpf
|
||||
xdp_metadata
|
||||
|
||||
@@ -18,7 +18,6 @@ extensions = [
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.imgmath',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx_rtd_theme',
|
||||
'breathe',
|
||||
]
|
||||
|
||||
|
||||
@@ -56,16 +56,6 @@ described in more detail in the footnotes.
|
||||
| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_CONNECT`` | ``cgroup/connect_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_SENDMSG`` | ``cgroup/sendmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_RECVMSG`` | ``cgroup/recvmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETPEERNAME`` | ``cgroup/getpeername_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETSOCKNAME`` | ``cgroup/getsockname_unix`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
breathe
|
||||
sphinx_rtd_theme
|
||||
breathe
|
||||
@@ -37,14 +37,6 @@
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_CALL_REL(DST) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_JMP | BPF_CALL, \
|
||||
.dst_reg = 0, \
|
||||
.src_reg = BPF_PSEUDO_CALL, \
|
||||
.off = 0, \
|
||||
.imm = DST })
|
||||
|
||||
#define BPF_EXIT_INSN() \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_JMP | BPF_EXIT, \
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#ifndef __LINUX_KERNEL_H
|
||||
#define __LINUX_KERNEL_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
/* ld/ldx fields */
|
||||
#define BPF_DW 0x18 /* double word (64-bit) */
|
||||
#define BPF_MEMSX 0x80 /* load with sign extension */
|
||||
#define BPF_ATOMIC 0xc0 /* atomic memory ops - op type in immediate */
|
||||
#define BPF_XADD 0xc0 /* exclusive add - legacy name */
|
||||
|
||||
@@ -42,7 +41,6 @@
|
||||
#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
|
||||
#define BPF_JSLT 0xc0 /* SLT is signed, '<' */
|
||||
#define BPF_JSLE 0xd0 /* SLE is signed, '<=' */
|
||||
#define BPF_JCOND 0xe0 /* conditional pseudo jumps: may_goto, goto_or_nop */
|
||||
#define BPF_CALL 0x80 /* function call */
|
||||
#define BPF_EXIT 0x90 /* function return */
|
||||
|
||||
@@ -51,10 +49,6 @@
|
||||
#define BPF_XCHG (0xe0 | BPF_FETCH) /* atomic exchange */
|
||||
#define BPF_CMPXCHG (0xf0 | BPF_FETCH) /* atomic compare-and-write */
|
||||
|
||||
enum bpf_cond_pseudo_jmp {
|
||||
BPF_MAY_GOTO = 0,
|
||||
};
|
||||
|
||||
/* Register numbers */
|
||||
enum {
|
||||
BPF_REG_0 = 0,
|
||||
@@ -82,29 +76,12 @@ struct bpf_insn {
|
||||
__s32 imm; /* signed immediate constant */
|
||||
};
|
||||
|
||||
/* Deprecated: use struct bpf_lpm_trie_key_u8 (when the "data" member is needed for
|
||||
* byte access) or struct bpf_lpm_trie_key_hdr (when using an alternative type for
|
||||
* the trailing flexible array member) instead.
|
||||
*/
|
||||
/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
|
||||
struct bpf_lpm_trie_key {
|
||||
__u32 prefixlen; /* up to 32 for AF_INET, 128 for AF_INET6 */
|
||||
__u8 data[0]; /* Arbitrary size */
|
||||
};
|
||||
|
||||
/* Header for bpf_lpm_trie_key structs */
|
||||
struct bpf_lpm_trie_key_hdr {
|
||||
__u32 prefixlen;
|
||||
};
|
||||
|
||||
/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry, with trailing byte array. */
|
||||
struct bpf_lpm_trie_key_u8 {
|
||||
union {
|
||||
struct bpf_lpm_trie_key_hdr hdr;
|
||||
__u32 prefixlen;
|
||||
};
|
||||
__u8 data[]; /* Arbitrary size */
|
||||
};
|
||||
|
||||
struct bpf_cgroup_storage_key {
|
||||
__u64 cgroup_inode_id; /* cgroup inode id */
|
||||
__u32 attach_type; /* program attach type (enum bpf_attach_type) */
|
||||
@@ -639,11 +616,7 @@ union bpf_iter_link_info {
|
||||
* to NULL to begin the batched operation. After each subsequent
|
||||
* **BPF_MAP_LOOKUP_BATCH**, the caller should pass the resultant
|
||||
* *out_batch* as the *in_batch* for the next operation to
|
||||
* continue iteration from the current point. Both *in_batch* and
|
||||
* *out_batch* must point to memory large enough to hold a key,
|
||||
* except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH,
|
||||
* LRU_HASH, LRU_PERCPU_HASH}**, for which batch parameters
|
||||
* must be at least 4 bytes wide regardless of key size.
|
||||
* continue iteration from the current point.
|
||||
*
|
||||
* The *keys* and *values* are output parameters which must point
|
||||
* to memory large enough to hold *count* items based on the key
|
||||
@@ -873,36 +846,6 @@ union bpf_iter_link_info {
|
||||
* Returns zero on success. On error, -1 is returned and *errno*
|
||||
* is set appropriately.
|
||||
*
|
||||
* BPF_TOKEN_CREATE
|
||||
* Description
|
||||
* Create BPF token with embedded information about what
|
||||
* BPF-related functionality it allows:
|
||||
* - a set of allowed bpf() syscall commands;
|
||||
* - a set of allowed BPF map types to be created with
|
||||
* BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed;
|
||||
* - a set of allowed BPF program types and BPF program attach
|
||||
* types to be loaded with BPF_PROG_LOAD command, if
|
||||
* BPF_PROG_LOAD itself is allowed.
|
||||
*
|
||||
* BPF token is created (derived) from an instance of BPF FS,
|
||||
* assuming it has necessary delegation mount options specified.
|
||||
* This BPF token can be passed as an extra parameter to various
|
||||
* bpf() syscall commands to grant BPF subsystem functionality to
|
||||
* unprivileged processes.
|
||||
*
|
||||
* When created, BPF token is "associated" with the owning
|
||||
* user namespace of BPF FS instance (super block) that it was
|
||||
* derived from, and subsequent BPF operations performed with
|
||||
* BPF token would be performing capabilities checks (i.e.,
|
||||
* CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within
|
||||
* that user namespace. Without BPF token, such capabilities
|
||||
* have to be granted in init user namespace, making bpf()
|
||||
* syscall incompatible with user namespace, for the most part.
|
||||
*
|
||||
* Return
|
||||
* A new file descriptor (a nonnegative integer), or -1 if an
|
||||
* error occurred (in which case, *errno* is set appropriately).
|
||||
*
|
||||
* NOTES
|
||||
* eBPF objects (maps and programs) can be shared between processes.
|
||||
*
|
||||
@@ -957,8 +900,6 @@ enum bpf_cmd {
|
||||
BPF_ITER_CREATE,
|
||||
BPF_LINK_DETACH,
|
||||
BPF_PROG_BIND_MAP,
|
||||
BPF_TOKEN_CREATE,
|
||||
__MAX_BPF_CMD,
|
||||
};
|
||||
|
||||
enum bpf_map_type {
|
||||
@@ -990,14 +931,7 @@ enum bpf_map_type {
|
||||
*/
|
||||
BPF_MAP_TYPE_CGROUP_STORAGE = BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED,
|
||||
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED,
|
||||
/* BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE is available to bpf programs
|
||||
* attaching to a cgroup. The new mechanism (BPF_MAP_TYPE_CGRP_STORAGE +
|
||||
* local percpu kptr) supports all BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
|
||||
* functionality and more. So mark * BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
|
||||
* deprecated.
|
||||
*/
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED,
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
|
||||
BPF_MAP_TYPE_QUEUE,
|
||||
BPF_MAP_TYPE_STACK,
|
||||
BPF_MAP_TYPE_SK_STORAGE,
|
||||
@@ -1009,8 +943,6 @@ enum bpf_map_type {
|
||||
BPF_MAP_TYPE_BLOOM_FILTER,
|
||||
BPF_MAP_TYPE_USER_RINGBUF,
|
||||
BPF_MAP_TYPE_CGRP_STORAGE,
|
||||
BPF_MAP_TYPE_ARENA,
|
||||
__MAX_BPF_MAP_TYPE
|
||||
};
|
||||
|
||||
/* Note that tracing related programs such as
|
||||
@@ -1055,7 +987,6 @@ enum bpf_prog_type {
|
||||
BPF_PROG_TYPE_SK_LOOKUP,
|
||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||
BPF_PROG_TYPE_NETFILTER,
|
||||
__MAX_BPF_PROG_TYPE
|
||||
};
|
||||
|
||||
enum bpf_attach_type {
|
||||
@@ -1105,16 +1036,6 @@ enum bpf_attach_type {
|
||||
BPF_LSM_CGROUP,
|
||||
BPF_STRUCT_OPS,
|
||||
BPF_NETFILTER,
|
||||
BPF_TCX_INGRESS,
|
||||
BPF_TCX_EGRESS,
|
||||
BPF_TRACE_UPROBE_MULTI,
|
||||
BPF_CGROUP_UNIX_CONNECT,
|
||||
BPF_CGROUP_UNIX_SENDMSG,
|
||||
BPF_CGROUP_UNIX_RECVMSG,
|
||||
BPF_CGROUP_UNIX_GETPEERNAME,
|
||||
BPF_CGROUP_UNIX_GETSOCKNAME,
|
||||
BPF_NETKIT_PRIMARY,
|
||||
BPF_NETKIT_PEER,
|
||||
__MAX_BPF_ATTACH_TYPE
|
||||
};
|
||||
|
||||
@@ -1132,22 +1053,8 @@ enum bpf_link_type {
|
||||
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
||||
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
||||
BPF_LINK_TYPE_NETFILTER = 10,
|
||||
BPF_LINK_TYPE_TCX = 11,
|
||||
BPF_LINK_TYPE_UPROBE_MULTI = 12,
|
||||
BPF_LINK_TYPE_NETKIT = 13,
|
||||
__MAX_BPF_LINK_TYPE,
|
||||
};
|
||||
|
||||
#define MAX_BPF_LINK_TYPE __MAX_BPF_LINK_TYPE
|
||||
|
||||
enum bpf_perf_event_type {
|
||||
BPF_PERF_EVENT_UNSPEC = 0,
|
||||
BPF_PERF_EVENT_UPROBE = 1,
|
||||
BPF_PERF_EVENT_URETPROBE = 2,
|
||||
BPF_PERF_EVENT_KPROBE = 3,
|
||||
BPF_PERF_EVENT_KRETPROBE = 4,
|
||||
BPF_PERF_EVENT_TRACEPOINT = 5,
|
||||
BPF_PERF_EVENT_EVENT = 6,
|
||||
MAX_BPF_LINK_TYPE,
|
||||
};
|
||||
|
||||
/* cgroup-bpf attach flags used in BPF_PROG_ATTACH command
|
||||
@@ -1196,12 +1103,7 @@ enum bpf_perf_event_type {
|
||||
*/
|
||||
#define BPF_F_ALLOW_OVERRIDE (1U << 0)
|
||||
#define BPF_F_ALLOW_MULTI (1U << 1)
|
||||
/* Generic attachment flags. */
|
||||
#define BPF_F_REPLACE (1U << 2)
|
||||
#define BPF_F_BEFORE (1U << 3)
|
||||
#define BPF_F_AFTER (1U << 4)
|
||||
#define BPF_F_ID (1U << 5)
|
||||
#define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
|
||||
|
||||
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
|
||||
* verifier will perform strict alignment checking as if the kernel
|
||||
@@ -1263,27 +1165,10 @@ enum bpf_perf_event_type {
|
||||
*/
|
||||
#define BPF_F_XDP_DEV_BOUND_ONLY (1U << 6)
|
||||
|
||||
/* The verifier internal test flag. Behavior is undefined */
|
||||
#define BPF_F_TEST_REG_INVARIANTS (1U << 7)
|
||||
|
||||
/* link_create.kprobe_multi.flags used in LINK_CREATE command for
|
||||
* BPF_TRACE_KPROBE_MULTI attach type to create return probe.
|
||||
*/
|
||||
enum {
|
||||
BPF_F_KPROBE_MULTI_RETURN = (1U << 0)
|
||||
};
|
||||
|
||||
/* link_create.uprobe_multi.flags used in LINK_CREATE command for
|
||||
* BPF_TRACE_UPROBE_MULTI attach type to create return probe.
|
||||
*/
|
||||
enum {
|
||||
BPF_F_UPROBE_MULTI_RETURN = (1U << 0)
|
||||
};
|
||||
|
||||
/* link_create.netfilter.flags used in LINK_CREATE command for
|
||||
* BPF_PROG_TYPE_NETFILTER to enable IP packet defragmentation.
|
||||
*/
|
||||
#define BPF_F_NETFILTER_IP_DEFRAG (1U << 0)
|
||||
#define BPF_F_KPROBE_MULTI_RETURN (1U << 0)
|
||||
|
||||
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
||||
* the following extensions:
|
||||
@@ -1339,10 +1224,6 @@ enum {
|
||||
*/
|
||||
#define BPF_PSEUDO_KFUNC_CALL 2
|
||||
|
||||
enum bpf_addr_space_cast {
|
||||
BPF_ADDR_SPACE_CAST = 1,
|
||||
};
|
||||
|
||||
/* flags for BPF_MAP_UPDATE_ELEM command */
|
||||
enum {
|
||||
BPF_ANY = 0, /* create new element or update existing */
|
||||
@@ -1395,18 +1276,6 @@ enum {
|
||||
|
||||
/* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */
|
||||
BPF_F_PATH_FD = (1U << 14),
|
||||
|
||||
/* Flag for value_type_btf_obj_fd, the fd is available */
|
||||
BPF_F_VTYPE_BTF_OBJ_FD = (1U << 15),
|
||||
|
||||
/* BPF token FD is passed in a corresponding command's token_fd field */
|
||||
BPF_F_TOKEN_FD = (1U << 16),
|
||||
|
||||
/* When user space page faults in bpf_arena send SIGSEGV instead of inserting new page */
|
||||
BPF_F_SEGV_ON_FAULT = (1U << 17),
|
||||
|
||||
/* Do not translate kernel bpf_arena pointers to user pointers */
|
||||
BPF_F_NO_USER_CONV = (1U << 18),
|
||||
};
|
||||
|
||||
/* Flags for BPF_PROG_QUERY. */
|
||||
@@ -1478,20 +1347,8 @@ union bpf_attr {
|
||||
* BPF_MAP_TYPE_BLOOM_FILTER - the lowest 4 bits indicate the
|
||||
* number of hash functions (if 0, the bloom filter will default
|
||||
* to using 5 hash functions).
|
||||
*
|
||||
* BPF_MAP_TYPE_ARENA - contains the address where user space
|
||||
* is going to mmap() the arena. It has to be page aligned.
|
||||
*/
|
||||
__u64 map_extra;
|
||||
|
||||
__s32 value_type_btf_obj_fd; /* fd pointing to a BTF
|
||||
* type data for
|
||||
* btf_vmlinux_value_type_id.
|
||||
*/
|
||||
/* BPF token FD to use with BPF_MAP_CREATE operation.
|
||||
* If provided, map_flags should have BPF_F_TOKEN_FD flag set.
|
||||
*/
|
||||
__s32 map_token_fd;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||
@@ -1561,10 +1418,6 @@ union bpf_attr {
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
/* BPF token FD to use with BPF_PROG_LOAD operation.
|
||||
* If provided, prog_flags should have BPF_F_TOKEN_FD flag set.
|
||||
*/
|
||||
__s32 prog_token_fd;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||
@@ -1581,19 +1434,14 @@ union bpf_attr {
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
|
||||
union {
|
||||
__u32 target_fd; /* target object to attach to or ... */
|
||||
__u32 target_ifindex; /* target ifindex */
|
||||
};
|
||||
__u32 attach_bpf_fd;
|
||||
__u32 target_fd; /* container object to attach to */
|
||||
__u32 attach_bpf_fd; /* eBPF program to attach */
|
||||
__u32 attach_type;
|
||||
__u32 attach_flags;
|
||||
__u32 replace_bpf_fd;
|
||||
union {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
};
|
||||
__u64 expected_revision;
|
||||
__u32 replace_bpf_fd; /* previously attached eBPF
|
||||
* program to replace if
|
||||
* BPF_F_REPLACE is used
|
||||
*/
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
||||
@@ -1639,33 +1487,21 @@ union bpf_attr {
|
||||
} info;
|
||||
|
||||
struct { /* anonymous struct used by BPF_PROG_QUERY command */
|
||||
union {
|
||||
__u32 target_fd; /* target object to query or ... */
|
||||
__u32 target_ifindex; /* target ifindex */
|
||||
};
|
||||
__u32 target_fd; /* container object to query */
|
||||
__u32 attach_type;
|
||||
__u32 query_flags;
|
||||
__u32 attach_flags;
|
||||
__aligned_u64 prog_ids;
|
||||
union {
|
||||
__u32 prog_cnt;
|
||||
__u32 count;
|
||||
};
|
||||
__u32 :32;
|
||||
__u32 prog_cnt;
|
||||
/* output: per-program attach_flags.
|
||||
* not allowed to be set during effective query.
|
||||
*/
|
||||
__aligned_u64 prog_attach_flags;
|
||||
__aligned_u64 link_ids;
|
||||
__aligned_u64 link_attach_flags;
|
||||
__u64 revision;
|
||||
} query;
|
||||
|
||||
struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */
|
||||
__u64 name;
|
||||
__u32 prog_fd;
|
||||
__u32 :32;
|
||||
__aligned_u64 cookie;
|
||||
__u64 name;
|
||||
__u32 prog_fd;
|
||||
} raw_tracepoint;
|
||||
|
||||
struct { /* anonymous struct for BPF_BTF_LOAD */
|
||||
@@ -1679,11 +1515,6 @@ union bpf_attr {
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
*/
|
||||
__u32 btf_log_true_size;
|
||||
__u32 btf_flags;
|
||||
/* BPF token FD to use with BPF_BTF_LOAD operation.
|
||||
* If provided, btf_flags should have BPF_F_TOKEN_FD flag set.
|
||||
*/
|
||||
__s32 btf_token_fd;
|
||||
};
|
||||
|
||||
struct {
|
||||
@@ -1708,13 +1539,13 @@ union bpf_attr {
|
||||
__u32 map_fd; /* struct_ops to attach */
|
||||
};
|
||||
union {
|
||||
__u32 target_fd; /* target object to attach to or ... */
|
||||
__u32 target_ifindex; /* target ifindex */
|
||||
__u32 target_fd; /* object to attach to */
|
||||
__u32 target_ifindex; /* target ifindex */
|
||||
};
|
||||
__u32 attach_type; /* attach type */
|
||||
__u32 flags; /* extra flags */
|
||||
union {
|
||||
__u32 target_btf_id; /* btf_id of target to attach to */
|
||||
__u32 target_btf_id; /* btf_id of target to attach to */
|
||||
struct {
|
||||
__aligned_u64 iter_info; /* extra bpf_iter_link_info */
|
||||
__u32 iter_info_len; /* iter_info length */
|
||||
@@ -1748,29 +1579,6 @@ union bpf_attr {
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
struct {
|
||||
union {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
};
|
||||
__u64 expected_revision;
|
||||
} tcx;
|
||||
struct {
|
||||
__aligned_u64 path;
|
||||
__aligned_u64 offsets;
|
||||
__aligned_u64 ref_ctr_offsets;
|
||||
__aligned_u64 cookies;
|
||||
__u32 cnt;
|
||||
__u32 flags;
|
||||
__u32 pid;
|
||||
} uprobe_multi;
|
||||
struct {
|
||||
union {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
};
|
||||
__u64 expected_revision;
|
||||
} netkit;
|
||||
};
|
||||
} link_create;
|
||||
|
||||
@@ -1814,11 +1622,6 @@ union bpf_attr {
|
||||
__u32 flags; /* extra flags */
|
||||
} prog_bind_map;
|
||||
|
||||
struct { /* struct used by BPF_TOKEN_CREATE command */
|
||||
__u32 flags;
|
||||
__u32 bpffs_fd;
|
||||
} token_create;
|
||||
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/* The description below is an attempt at providing documentation to eBPF
|
||||
@@ -2094,9 +1897,7 @@ union bpf_attr {
|
||||
* performed again, if the helper is used in combination with
|
||||
* direct packet access.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure. Positive
|
||||
* error indicates a potential drop or congestion in the target
|
||||
* device. The particular positive error codes are not defined.
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* u64 bpf_get_current_pid_tgid(void)
|
||||
* Description
|
||||
@@ -2829,8 +2630,8 @@ union bpf_attr {
|
||||
* *bpf_socket* should be one of the following:
|
||||
*
|
||||
* * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.
|
||||
* * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**,
|
||||
* **BPF_CGROUP_INET6_CONNECT** and **BPF_CGROUP_UNIX_CONNECT**.
|
||||
* * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**
|
||||
* and **BPF_CGROUP_INET6_CONNECT**.
|
||||
*
|
||||
* This helper actually implements a subset of **setsockopt()**.
|
||||
* It supports the following *level*\ s:
|
||||
@@ -3068,8 +2869,8 @@ union bpf_attr {
|
||||
* *bpf_socket* should be one of the following:
|
||||
*
|
||||
* * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.
|
||||
* * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**,
|
||||
* **BPF_CGROUP_INET6_CONNECT** and **BPF_CGROUP_UNIX_CONNECT**.
|
||||
* * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**
|
||||
* and **BPF_CGROUP_INET6_CONNECT**.
|
||||
*
|
||||
* This helper actually implements a subset of **getsockopt()**.
|
||||
* It supports the same set of *optname*\ s that is supported by
|
||||
@@ -3389,11 +3190,6 @@ union bpf_attr {
|
||||
* and *params*->smac will not be set as output. A common
|
||||
* use case is to call **bpf_redirect_neigh**\ () after
|
||||
* doing **bpf_fib_lookup**\ ().
|
||||
* **BPF_FIB_LOOKUP_SRC**
|
||||
* Derive and set source IP addr in *params*->ipv{4,6}_src
|
||||
* for the nexthop. If the src addr cannot be derived,
|
||||
* **BPF_FIB_LKUP_RET_NO_SRC_ADDR** is returned. In this
|
||||
* case, *params*->dmac and *params*->smac are not set either.
|
||||
*
|
||||
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||
* **struct sk_buff** tc cls_act programs.
|
||||
@@ -4363,6 +4159,9 @@ union bpf_attr {
|
||||
* **-EOPNOTSUPP** if the operation is not supported, for example
|
||||
* a call from outside of TC ingress.
|
||||
*
|
||||
* **-ESOCKTNOSUPPORT** if the socket type is not supported
|
||||
* (reuseport).
|
||||
*
|
||||
* long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags)
|
||||
* Description
|
||||
* Helper is overloaded depending on BPF program type. This
|
||||
@@ -4627,8 +4426,6 @@ union bpf_attr {
|
||||
* long bpf_get_task_stack(struct task_struct *task, void *buf, u32 size, u64 flags)
|
||||
* Description
|
||||
* Return a user or a kernel stack in bpf program provided buffer.
|
||||
* Note: the user stack will only be populated if the *task* is
|
||||
* the current task; all other tasks will return -EOPNOTSUPP.
|
||||
* To achieve this, the helper needs *task*, which is a valid
|
||||
* pointer to **struct task_struct**. To store the stacktrace, the
|
||||
* bpf program provides *buf* with a nonnegative *size*.
|
||||
@@ -4640,7 +4437,6 @@ union bpf_attr {
|
||||
*
|
||||
* **BPF_F_USER_STACK**
|
||||
* Collect a user space stack instead of a kernel stack.
|
||||
* The *task* must be the current task.
|
||||
* **BPF_F_USER_BUILD_ID**
|
||||
* Collect buildid+offset instead of ips for user stack,
|
||||
* only valid if **BPF_F_USER_STACK** is also specified.
|
||||
@@ -4944,9 +4740,9 @@ union bpf_attr {
|
||||
* going through the CPU's backlog queue.
|
||||
*
|
||||
* The *flags* argument is reserved and must be 0. The helper is
|
||||
* currently only supported for tc BPF program types at the
|
||||
* ingress hook and for veth and netkit target device types. The
|
||||
* peer device must reside in a different network namespace.
|
||||
* currently only supported for tc BPF program types at the ingress
|
||||
* hook and for veth device types. The peer device must reside in a
|
||||
* different network namespace.
|
||||
* Return
|
||||
* The helper returns **TC_ACT_REDIRECT** on success or
|
||||
* **TC_ACT_SHOT** on error.
|
||||
@@ -5229,8 +5025,6 @@ union bpf_attr {
|
||||
* **BPF_F_TIMER_ABS**
|
||||
* Start the timer in absolute expire value instead of the
|
||||
* default relative one.
|
||||
* **BPF_F_TIMER_CPU_PIN**
|
||||
* Timer will be pinned to the CPU of the caller.
|
||||
*
|
||||
* Return
|
||||
* 0 on success.
|
||||
@@ -5250,14 +5044,9 @@ union bpf_attr {
|
||||
* u64 bpf_get_func_ip(void *ctx)
|
||||
* Description
|
||||
* Get address of the traced function (for tracing and kprobe programs).
|
||||
*
|
||||
* When called for kprobe program attached as uprobe it returns
|
||||
* probe address for both entry and return uprobe.
|
||||
*
|
||||
* Return
|
||||
* Address of the traced function for kprobe.
|
||||
* Address of the traced function.
|
||||
* 0 for kprobes placed within the function (not at the entry).
|
||||
* Address of the probe for uprobe and return uprobe.
|
||||
*
|
||||
* u64 bpf_get_attach_cookie(void *ctx)
|
||||
* Description
|
||||
@@ -6398,19 +6187,6 @@ struct bpf_sock_tuple {
|
||||
};
|
||||
};
|
||||
|
||||
/* (Simplified) user return codes for tcx prog type.
|
||||
* A valid tcx program must return one of these defined values. All other
|
||||
* return codes are reserved for future use. Must remain compatible with
|
||||
* their TC_ACT_* counter-parts. For compatibility in behavior, unknown
|
||||
* return codes are mapped to TCX_NEXT.
|
||||
*/
|
||||
enum tcx_action_base {
|
||||
TCX_NEXT = -1,
|
||||
TCX_PASS = 0,
|
||||
TCX_DROP = 2,
|
||||
TCX_REDIRECT = 7,
|
||||
};
|
||||
|
||||
struct bpf_xdp_sock {
|
||||
__u32 queue_id;
|
||||
};
|
||||
@@ -6592,7 +6368,7 @@ struct bpf_map_info {
|
||||
__u32 btf_id;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
__u32 btf_vmlinux_id;
|
||||
__u32 :32; /* alignment pad */
|
||||
__u64 map_extra;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
@@ -6663,63 +6439,6 @@ struct bpf_link_info {
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
struct {
|
||||
__aligned_u64 addrs;
|
||||
__u32 count; /* in/out: kprobe_multi function count */
|
||||
__u32 flags;
|
||||
__u64 missed;
|
||||
__aligned_u64 cookies;
|
||||
} kprobe_multi;
|
||||
struct {
|
||||
__aligned_u64 path;
|
||||
__aligned_u64 offsets;
|
||||
__aligned_u64 ref_ctr_offsets;
|
||||
__aligned_u64 cookies;
|
||||
__u32 path_size; /* in/out: real path size on success, including zero byte */
|
||||
__u32 count; /* in/out: uprobe_multi offsets/ref_ctr_offsets/cookies count */
|
||||
__u32 flags;
|
||||
__u32 pid;
|
||||
} uprobe_multi;
|
||||
struct {
|
||||
__u32 type; /* enum bpf_perf_event_type */
|
||||
__u32 :32;
|
||||
union {
|
||||
struct {
|
||||
__aligned_u64 file_name; /* in/out */
|
||||
__u32 name_len;
|
||||
__u32 offset; /* offset from file_name */
|
||||
__u64 cookie;
|
||||
} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
|
||||
struct {
|
||||
__aligned_u64 func_name; /* in/out */
|
||||
__u32 name_len;
|
||||
__u32 offset; /* offset from func_name */
|
||||
__u64 addr;
|
||||
__u64 missed;
|
||||
__u64 cookie;
|
||||
} kprobe; /* BPF_PERF_EVENT_KPROBE, BPF_PERF_EVENT_KRETPROBE */
|
||||
struct {
|
||||
__aligned_u64 tp_name; /* in/out */
|
||||
__u32 name_len;
|
||||
__u32 :32;
|
||||
__u64 cookie;
|
||||
} tracepoint; /* BPF_PERF_EVENT_TRACEPOINT */
|
||||
struct {
|
||||
__u64 config;
|
||||
__u32 type;
|
||||
__u32 :32;
|
||||
__u64 cookie;
|
||||
} event; /* BPF_PERF_EVENT_EVENT */
|
||||
};
|
||||
} perf_event;
|
||||
struct {
|
||||
__u32 ifindex;
|
||||
__u32 attach_type;
|
||||
} tcx;
|
||||
struct {
|
||||
__u32 ifindex;
|
||||
__u32 attach_type;
|
||||
} netkit;
|
||||
};
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
@@ -7016,7 +6735,6 @@ enum {
|
||||
BPF_TCP_LISTEN,
|
||||
BPF_TCP_CLOSING, /* Now a valid state */
|
||||
BPF_TCP_NEW_SYN_RECV,
|
||||
BPF_TCP_BOUND_INACTIVE,
|
||||
|
||||
BPF_TCP_MAX_STATES /* Leave at the end! */
|
||||
};
|
||||
@@ -7119,7 +6837,6 @@ enum {
|
||||
BPF_FIB_LOOKUP_OUTPUT = (1U << 1),
|
||||
BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2),
|
||||
BPF_FIB_LOOKUP_TBID = (1U << 3),
|
||||
BPF_FIB_LOOKUP_SRC = (1U << 4),
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -7132,7 +6849,6 @@ enum {
|
||||
BPF_FIB_LKUP_RET_UNSUPP_LWT, /* fwd requires encapsulation */
|
||||
BPF_FIB_LKUP_RET_NO_NEIGH, /* no neighbor entry for nh */
|
||||
BPF_FIB_LKUP_RET_FRAG_NEEDED, /* fragmentation required to fwd */
|
||||
BPF_FIB_LKUP_RET_NO_SRC_ADDR, /* failed to derive IP src addr */
|
||||
};
|
||||
|
||||
struct bpf_fib_lookup {
|
||||
@@ -7167,9 +6883,6 @@ struct bpf_fib_lookup {
|
||||
__u32 rt_metric;
|
||||
};
|
||||
|
||||
/* input: source address to consider for lookup
|
||||
* output: source address result from lookup
|
||||
*/
|
||||
union {
|
||||
__be32 ipv4_src;
|
||||
__u32 ipv6_src[4]; /* in6_addr; network order */
|
||||
@@ -7282,31 +6995,38 @@ struct bpf_spin_lock {
|
||||
};
|
||||
|
||||
struct bpf_timer {
|
||||
__u64 __opaque[2];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_dynptr {
|
||||
__u64 __opaque[2];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_list_head {
|
||||
__u64 __opaque[2];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_list_node {
|
||||
__u64 __opaque[3];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_rb_root {
|
||||
__u64 __opaque[2];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_rb_node {
|
||||
__u64 __opaque[4];
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_refcount {
|
||||
__u32 __opaque[1];
|
||||
__u32 :32;
|
||||
} __attribute__((aligned(4)));
|
||||
|
||||
struct bpf_sysctl {
|
||||
@@ -7462,11 +7182,9 @@ struct bpf_core_relo {
|
||||
* Flags to control bpf_timer_start() behaviour.
|
||||
* - BPF_F_TIMER_ABS: Timeout passed is absolute time, by default it is
|
||||
* relative to current time.
|
||||
* - BPF_F_TIMER_CPU_PIN: Timer will be pinned to the CPU of the caller.
|
||||
*/
|
||||
enum {
|
||||
BPF_F_TIMER_ABS = (1ULL << 0),
|
||||
BPF_F_TIMER_CPU_PIN = (1ULL << 1),
|
||||
};
|
||||
|
||||
/* BPF numbers iterator state */
|
||||
|
||||
@@ -112,12 +112,4 @@
|
||||
|
||||
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
|
||||
|
||||
/* Flags for name_to_handle_at(2). We reuse AT_ flag space to save bits... */
|
||||
#define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to
|
||||
compare object identity and may not
|
||||
be usable to open_by_handle_at(2) */
|
||||
#if defined(__KERNEL__)
|
||||
#define AT_GETATTR_NOSEC 0x80000000
|
||||
#endif
|
||||
|
||||
#endif /* _UAPI_LINUX_FCNTL_H */
|
||||
|
||||
@@ -211,9 +211,6 @@ struct rtnl_link_stats {
|
||||
* @rx_nohandler: Number of packets received on the interface
|
||||
* but dropped by the networking stack because the device is
|
||||
* not designated to receive packets (e.g. backup link in a bond).
|
||||
*
|
||||
* @rx_otherhost_dropped: Number of packets dropped due to mismatch
|
||||
* in destination MAC address.
|
||||
*/
|
||||
struct rtnl_link_stats64 {
|
||||
__u64 rx_packets;
|
||||
@@ -246,23 +243,6 @@ struct rtnl_link_stats64 {
|
||||
__u64 rx_compressed;
|
||||
__u64 tx_compressed;
|
||||
__u64 rx_nohandler;
|
||||
|
||||
__u64 rx_otherhost_dropped;
|
||||
};
|
||||
|
||||
/* Subset of link stats useful for in-HW collection. Meaning of the fields is as
|
||||
* for struct rtnl_link_stats64.
|
||||
*/
|
||||
struct rtnl_hw_stats64 {
|
||||
__u64 rx_packets;
|
||||
__u64 tx_packets;
|
||||
__u64 rx_bytes;
|
||||
__u64 tx_bytes;
|
||||
__u64 rx_errors;
|
||||
__u64 tx_errors;
|
||||
__u64 rx_dropped;
|
||||
__u64 tx_dropped;
|
||||
__u64 multicast;
|
||||
};
|
||||
|
||||
/* The struct should be in sync with struct ifmap */
|
||||
@@ -370,13 +350,7 @@ enum {
|
||||
IFLA_GRO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SEGS,
|
||||
IFLA_ALLMULTI, /* Allmulti count: > 0 means acts ALLMULTI */
|
||||
|
||||
IFLA_DEVLINK_PORT,
|
||||
|
||||
IFLA_GSO_IPV4_MAX_SIZE,
|
||||
IFLA_GRO_IPV4_MAX_SIZE,
|
||||
IFLA_DPLL_PIN,
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
@@ -565,12 +539,6 @@ enum {
|
||||
IFLA_BRPORT_MRP_IN_OPEN,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
|
||||
IFLA_BRPORT_LOCKED,
|
||||
IFLA_BRPORT_MAB,
|
||||
IFLA_BRPORT_MCAST_N_GROUPS,
|
||||
IFLA_BRPORT_MCAST_MAX_GROUPS,
|
||||
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
|
||||
IFLA_BRPORT_BACKUP_NHID,
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
@@ -748,79 +716,7 @@ enum ipvlan_mode {
|
||||
#define IPVLAN_F_PRIVATE 0x01
|
||||
#define IPVLAN_F_VEPA 0x02
|
||||
|
||||
/* Tunnel RTM header */
|
||||
struct tunnel_msg {
|
||||
__u8 family;
|
||||
__u8 flags;
|
||||
__u16 reserved2;
|
||||
__u32 ifindex;
|
||||
};
|
||||
|
||||
/* netkit section */
|
||||
enum netkit_action {
|
||||
NETKIT_NEXT = -1,
|
||||
NETKIT_PASS = 0,
|
||||
NETKIT_DROP = 2,
|
||||
NETKIT_REDIRECT = 7,
|
||||
};
|
||||
|
||||
enum netkit_mode {
|
||||
NETKIT_L2,
|
||||
NETKIT_L3,
|
||||
};
|
||||
|
||||
enum {
|
||||
IFLA_NETKIT_UNSPEC,
|
||||
IFLA_NETKIT_PEER_INFO,
|
||||
IFLA_NETKIT_PRIMARY,
|
||||
IFLA_NETKIT_POLICY,
|
||||
IFLA_NETKIT_PEER_POLICY,
|
||||
IFLA_NETKIT_MODE,
|
||||
__IFLA_NETKIT_MAX,
|
||||
};
|
||||
#define IFLA_NETKIT_MAX (__IFLA_NETKIT_MAX - 1)
|
||||
|
||||
/* VXLAN section */
|
||||
|
||||
/* include statistics in the dump */
|
||||
#define TUNNEL_MSG_FLAG_STATS 0x01
|
||||
|
||||
#define TUNNEL_MSG_VALID_USER_FLAGS TUNNEL_MSG_FLAG_STATS
|
||||
|
||||
/* Embedded inside VXLAN_VNIFILTER_ENTRY_STATS */
|
||||
enum {
|
||||
VNIFILTER_ENTRY_STATS_UNSPEC,
|
||||
VNIFILTER_ENTRY_STATS_RX_BYTES,
|
||||
VNIFILTER_ENTRY_STATS_RX_PKTS,
|
||||
VNIFILTER_ENTRY_STATS_RX_DROPS,
|
||||
VNIFILTER_ENTRY_STATS_RX_ERRORS,
|
||||
VNIFILTER_ENTRY_STATS_TX_BYTES,
|
||||
VNIFILTER_ENTRY_STATS_TX_PKTS,
|
||||
VNIFILTER_ENTRY_STATS_TX_DROPS,
|
||||
VNIFILTER_ENTRY_STATS_TX_ERRORS,
|
||||
VNIFILTER_ENTRY_STATS_PAD,
|
||||
__VNIFILTER_ENTRY_STATS_MAX
|
||||
};
|
||||
#define VNIFILTER_ENTRY_STATS_MAX (__VNIFILTER_ENTRY_STATS_MAX - 1)
|
||||
|
||||
enum {
|
||||
VXLAN_VNIFILTER_ENTRY_UNSPEC,
|
||||
VXLAN_VNIFILTER_ENTRY_START,
|
||||
VXLAN_VNIFILTER_ENTRY_END,
|
||||
VXLAN_VNIFILTER_ENTRY_GROUP,
|
||||
VXLAN_VNIFILTER_ENTRY_GROUP6,
|
||||
VXLAN_VNIFILTER_ENTRY_STATS,
|
||||
__VXLAN_VNIFILTER_ENTRY_MAX
|
||||
};
|
||||
#define VXLAN_VNIFILTER_ENTRY_MAX (__VXLAN_VNIFILTER_ENTRY_MAX - 1)
|
||||
|
||||
enum {
|
||||
VXLAN_VNIFILTER_UNSPEC,
|
||||
VXLAN_VNIFILTER_ENTRY,
|
||||
__VXLAN_VNIFILTER_MAX
|
||||
};
|
||||
#define VXLAN_VNIFILTER_MAX (__VXLAN_VNIFILTER_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_VXLAN_UNSPEC,
|
||||
IFLA_VXLAN_ID,
|
||||
@@ -852,8 +748,6 @@ enum {
|
||||
IFLA_VXLAN_GPE,
|
||||
IFLA_VXLAN_TTL_INHERIT,
|
||||
IFLA_VXLAN_DF,
|
||||
IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */
|
||||
IFLA_VXLAN_LOCALBYPASS,
|
||||
__IFLA_VXLAN_MAX
|
||||
};
|
||||
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
|
||||
@@ -887,7 +781,6 @@ enum {
|
||||
IFLA_GENEVE_LABEL,
|
||||
IFLA_GENEVE_TTL_INHERIT,
|
||||
IFLA_GENEVE_DF,
|
||||
IFLA_GENEVE_INNER_PROTO_INHERIT,
|
||||
__IFLA_GENEVE_MAX
|
||||
};
|
||||
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
|
||||
@@ -933,8 +826,6 @@ enum {
|
||||
IFLA_GTP_FD1,
|
||||
IFLA_GTP_PDP_HASHSIZE,
|
||||
IFLA_GTP_ROLE,
|
||||
IFLA_GTP_CREATE_SOCKETS,
|
||||
IFLA_GTP_RESTART_COUNT,
|
||||
__IFLA_GTP_MAX,
|
||||
};
|
||||
#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
|
||||
@@ -974,7 +865,6 @@ enum {
|
||||
IFLA_BOND_AD_LACP_ACTIVE,
|
||||
IFLA_BOND_MISSED_MAX,
|
||||
IFLA_BOND_NS_IP6_TARGET,
|
||||
IFLA_BOND_COUPLED_CONTROL,
|
||||
__IFLA_BOND_MAX,
|
||||
};
|
||||
|
||||
@@ -1272,17 +1162,6 @@ enum {
|
||||
|
||||
#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1))
|
||||
|
||||
enum {
|
||||
IFLA_STATS_GETSET_UNSPEC,
|
||||
IFLA_STATS_GET_FILTERS, /* Nest of IFLA_STATS_LINK_xxx, each a u32 with
|
||||
* a filter mask for the corresponding group.
|
||||
*/
|
||||
IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS, /* 0 or 1 as u8 */
|
||||
__IFLA_STATS_GETSET_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_STATS_GETSET_MAX (__IFLA_STATS_GETSET_MAX - 1)
|
||||
|
||||
/* These are embedded into IFLA_STATS_LINK_XSTATS:
|
||||
* [IFLA_STATS_LINK_XSTATS]
|
||||
* -> [LINK_XSTATS_TYPE_xxx]
|
||||
@@ -1300,21 +1179,10 @@ enum {
|
||||
enum {
|
||||
IFLA_OFFLOAD_XSTATS_UNSPEC,
|
||||
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
|
||||
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
|
||||
__IFLA_OFFLOAD_XSTATS_MAX
|
||||
};
|
||||
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC,
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, /* u8 */
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, /* u8 */
|
||||
__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX,
|
||||
};
|
||||
#define IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX \
|
||||
(__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX - 1)
|
||||
|
||||
/* XDP section */
|
||||
|
||||
#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
|
||||
@@ -1413,14 +1281,4 @@ enum {
|
||||
|
||||
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
|
||||
|
||||
/* DSA section */
|
||||
|
||||
enum {
|
||||
IFLA_DSA_UNSPEC,
|
||||
IFLA_DSA_MASTER,
|
||||
__IFLA_DSA_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_DSA_MAX (__IFLA_DSA_MAX - 1)
|
||||
|
||||
#endif /* _UAPI_LINUX_IF_LINK_H */
|
||||
|
||||
@@ -25,21 +25,9 @@
|
||||
* application.
|
||||
*/
|
||||
#define XDP_USE_NEED_WAKEUP (1 << 3)
|
||||
/* By setting this option, userspace application indicates that it can
|
||||
* handle multiple descriptors per packet thus enabling AF_XDP to split
|
||||
* multi-buffer XDP frames into multiple Rx descriptors. Without this set
|
||||
* such frames will be dropped.
|
||||
*/
|
||||
#define XDP_USE_SG (1 << 4)
|
||||
|
||||
/* Flags for xsk_umem_config flags */
|
||||
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||
|
||||
/* Force checksum calculation in software. Can be used for testing or
|
||||
* working around potential HW issues. This option causes performance
|
||||
* degradation and only works in XDP_COPY mode.
|
||||
*/
|
||||
#define XDP_UMEM_TX_SW_CSUM (1 << 1)
|
||||
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||
|
||||
struct sockaddr_xdp {
|
||||
__u16 sxdp_family;
|
||||
@@ -82,7 +70,6 @@ struct xdp_umem_reg {
|
||||
__u32 chunk_size;
|
||||
__u32 headroom;
|
||||
__u32 flags;
|
||||
__u32 tx_metadata_len;
|
||||
};
|
||||
|
||||
struct xdp_statistics {
|
||||
@@ -112,41 +99,6 @@ struct xdp_options {
|
||||
#define XSK_UNALIGNED_BUF_ADDR_MASK \
|
||||
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||
|
||||
/* Request transmit timestamp. Upon completion, put it into tx_timestamp
|
||||
* field of union xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0)
|
||||
|
||||
/* Request transmit checksum offload. Checksum start position and offset
|
||||
* are communicated via csum_start and csum_offset fields of union
|
||||
* xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_CHECKSUM (1 << 1)
|
||||
|
||||
/* AF_XDP offloads request. 'request' union member is consumed by the driver
|
||||
* when the packet is being transmitted. 'completion' union member is
|
||||
* filled by the driver when the transmit completion arrives.
|
||||
*/
|
||||
struct xsk_tx_metadata {
|
||||
__u64 flags;
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* XDP_TXMD_FLAGS_CHECKSUM */
|
||||
|
||||
/* Offset from desc->addr where checksumming should start. */
|
||||
__u16 csum_start;
|
||||
/* Offset from csum_start where checksum should be stored. */
|
||||
__u16 csum_offset;
|
||||
} request;
|
||||
|
||||
struct {
|
||||
/* XDP_TXMD_FLAGS_TIMESTAMP */
|
||||
__u64 tx_timestamp;
|
||||
} completion;
|
||||
};
|
||||
};
|
||||
|
||||
/* Rx/Tx descriptor */
|
||||
struct xdp_desc {
|
||||
__u64 addr;
|
||||
@@ -156,14 +108,4 @@ struct xdp_desc {
|
||||
|
||||
/* UMEM descriptor is __u64 */
|
||||
|
||||
/* Flag indicating that the packet continues with the buffer pointed out by the
|
||||
* next frame in the ring. The end of the packet is signalled by setting this
|
||||
* bit to zero. For single buffer packets, every descriptor has 'options' set
|
||||
* to 0 and this maintains backward compatibility.
|
||||
*/
|
||||
#define XDP_PKT_CONTD (1 << 0)
|
||||
|
||||
/* TX packet carries valid metadata. */
|
||||
#define XDP_TX_METADATA (1 << 1)
|
||||
|
||||
#endif /* _LINUX_IF_XDP_H */
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
/**
|
||||
* enum netdev_xdp_act
|
||||
* @NETDEV_XDP_ACT_BASIC: XDP features set supported by all drivers
|
||||
* @NETDEV_XDP_ACT_BASIC: XDP feautues set supported by all drivers
|
||||
* (XDP_ABORTED, XDP_DROP, XDP_PASS, XDP_TX)
|
||||
* @NETDEV_XDP_ACT_REDIRECT: The netdev supports XDP_REDIRECT
|
||||
* @NETDEV_XDP_ACT_NDO_XMIT: This feature informs if netdev implements
|
||||
@@ -34,142 +34,28 @@ enum netdev_xdp_act {
|
||||
NETDEV_XDP_ACT_RX_SG = 32,
|
||||
NETDEV_XDP_ACT_NDO_XMIT_SG = 64,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XDP_ACT_MASK = 127,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netdev_xdp_rx_metadata
|
||||
* @NETDEV_XDP_RX_METADATA_TIMESTAMP: Device is capable of exposing receive HW
|
||||
* timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
* @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet
|
||||
* hash via bpf_xdp_metadata_rx_hash().
|
||||
* @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
|
||||
* packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
|
||||
*/
|
||||
enum netdev_xdp_rx_metadata {
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
|
||||
NETDEV_XDP_RX_METADATA_HASH = 2,
|
||||
NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netdev_xsk_flags
|
||||
* @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported
|
||||
* by the driver.
|
||||
* @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the
|
||||
* driver.
|
||||
*/
|
||||
enum netdev_xsk_flags {
|
||||
NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1,
|
||||
NETDEV_XSK_FLAGS_TX_CHECKSUM = 2,
|
||||
};
|
||||
|
||||
enum netdev_queue_type {
|
||||
NETDEV_QUEUE_TYPE_RX,
|
||||
NETDEV_QUEUE_TYPE_TX,
|
||||
};
|
||||
|
||||
enum netdev_qstats_scope {
|
||||
NETDEV_QSTATS_SCOPE_QUEUE = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_DEV_IFINDEX = 1,
|
||||
NETDEV_A_DEV_PAD,
|
||||
NETDEV_A_DEV_XDP_FEATURES,
|
||||
NETDEV_A_DEV_XDP_ZC_MAX_SEGS,
|
||||
NETDEV_A_DEV_XDP_RX_METADATA_FEATURES,
|
||||
NETDEV_A_DEV_XSK_FEATURES,
|
||||
|
||||
__NETDEV_A_DEV_MAX,
|
||||
NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_PAGE_POOL_ID = 1,
|
||||
NETDEV_A_PAGE_POOL_IFINDEX,
|
||||
NETDEV_A_PAGE_POOL_NAPI_ID,
|
||||
NETDEV_A_PAGE_POOL_INFLIGHT,
|
||||
NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
|
||||
NETDEV_A_PAGE_POOL_DETACH_TIME,
|
||||
|
||||
__NETDEV_A_PAGE_POOL_MAX,
|
||||
NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_PAGE_POOL_STATS_INFO = 1,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
|
||||
|
||||
__NETDEV_A_PAGE_POOL_STATS_MAX,
|
||||
NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_NAPI_IFINDEX = 1,
|
||||
NETDEV_A_NAPI_ID,
|
||||
NETDEV_A_NAPI_IRQ,
|
||||
NETDEV_A_NAPI_PID,
|
||||
|
||||
__NETDEV_A_NAPI_MAX,
|
||||
NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_QUEUE_ID = 1,
|
||||
NETDEV_A_QUEUE_IFINDEX,
|
||||
NETDEV_A_QUEUE_TYPE,
|
||||
NETDEV_A_QUEUE_NAPI_ID,
|
||||
|
||||
__NETDEV_A_QUEUE_MAX,
|
||||
NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_QSTATS_IFINDEX = 1,
|
||||
NETDEV_A_QSTATS_QUEUE_TYPE,
|
||||
NETDEV_A_QSTATS_QUEUE_ID,
|
||||
NETDEV_A_QSTATS_SCOPE,
|
||||
NETDEV_A_QSTATS_RX_PACKETS = 8,
|
||||
NETDEV_A_QSTATS_RX_BYTES,
|
||||
NETDEV_A_QSTATS_TX_PACKETS,
|
||||
NETDEV_A_QSTATS_TX_BYTES,
|
||||
NETDEV_A_QSTATS_RX_ALLOC_FAIL,
|
||||
|
||||
__NETDEV_A_QSTATS_MAX,
|
||||
NETDEV_A_QSTATS_MAX = (__NETDEV_A_QSTATS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_CMD_DEV_GET = 1,
|
||||
NETDEV_CMD_DEV_ADD_NTF,
|
||||
NETDEV_CMD_DEV_DEL_NTF,
|
||||
NETDEV_CMD_DEV_CHANGE_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_GET,
|
||||
NETDEV_CMD_PAGE_POOL_ADD_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_DEL_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_STATS_GET,
|
||||
NETDEV_CMD_QUEUE_GET,
|
||||
NETDEV_CMD_NAPI_GET,
|
||||
NETDEV_CMD_QSTATS_GET,
|
||||
|
||||
__NETDEV_CMD_MAX,
|
||||
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#define NETDEV_MCGRP_MGMT "mgmt"
|
||||
#define NETDEV_MCGRP_PAGE_POOL "page-pool"
|
||||
|
||||
#endif /* _UAPI_LINUX_NETDEV_H */
|
||||
|
||||
@@ -204,8 +204,6 @@ enum perf_branch_sample_type_shift {
|
||||
|
||||
PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */
|
||||
|
||||
PERF_SAMPLE_BRANCH_COUNTERS_SHIFT = 19, /* save occurrences of events on a branch */
|
||||
|
||||
PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
|
||||
};
|
||||
|
||||
@@ -237,8 +235,6 @@ enum perf_branch_sample_type {
|
||||
|
||||
PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,
|
||||
|
||||
PERF_SAMPLE_BRANCH_COUNTERS = 1U << PERF_SAMPLE_BRANCH_COUNTERS_SHIFT,
|
||||
|
||||
PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
|
||||
};
|
||||
|
||||
@@ -986,12 +982,6 @@ enum perf_event_type {
|
||||
* { u64 nr;
|
||||
* { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
|
||||
* { u64 from, to, flags } lbr[nr];
|
||||
* #
|
||||
* # The format of the counters is decided by the
|
||||
* # "branch_counter_nr" and "branch_counter_width",
|
||||
* # which are defined in the ABI.
|
||||
* #
|
||||
* { u64 counters; } cntr[nr] && PERF_SAMPLE_BRANCH_COUNTERS
|
||||
* } && PERF_SAMPLE_BRANCH_STACK
|
||||
*
|
||||
* { u64 abi; # enum perf_sample_regs_abi
|
||||
@@ -1349,8 +1339,7 @@ union perf_mem_data_src {
|
||||
#define PERF_MEM_LVLNUM_L2 0x02 /* L2 */
|
||||
#define PERF_MEM_LVLNUM_L3 0x03 /* L3 */
|
||||
#define PERF_MEM_LVLNUM_L4 0x04 /* L4 */
|
||||
/* 5-0x7 available */
|
||||
#define PERF_MEM_LVLNUM_UNC 0x08 /* Uncached */
|
||||
/* 5-0x8 available */
|
||||
#define PERF_MEM_LVLNUM_CXL 0x09 /* CXL */
|
||||
#define PERF_MEM_LVLNUM_IO 0x0a /* I/O */
|
||||
#define PERF_MEM_LVLNUM_ANY_CACHE 0x0b /* Any cache */
|
||||
@@ -1437,9 +1426,6 @@ struct perf_branch_entry {
|
||||
reserved:31;
|
||||
};
|
||||
|
||||
/* Size of used info bits in struct perf_branch_entry */
|
||||
#define PERF_BRANCH_ENTRY_INFO_BITS_MAX 33
|
||||
|
||||
union perf_sample_weight {
|
||||
__u64 full;
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
|
||||
@@ -204,6 +204,37 @@ struct tc_u32_pcnt {
|
||||
|
||||
#define TC_U32_MAXDEPTH 8
|
||||
|
||||
|
||||
/* RSVP filter */
|
||||
|
||||
enum {
|
||||
TCA_RSVP_UNSPEC,
|
||||
TCA_RSVP_CLASSID,
|
||||
TCA_RSVP_DST,
|
||||
TCA_RSVP_SRC,
|
||||
TCA_RSVP_PINFO,
|
||||
TCA_RSVP_POLICE,
|
||||
TCA_RSVP_ACT,
|
||||
__TCA_RSVP_MAX
|
||||
};
|
||||
|
||||
#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
|
||||
|
||||
struct tc_rsvp_gpi {
|
||||
__u32 key;
|
||||
__u32 mask;
|
||||
int offset;
|
||||
};
|
||||
|
||||
struct tc_rsvp_pinfo {
|
||||
struct tc_rsvp_gpi dpi;
|
||||
struct tc_rsvp_gpi spi;
|
||||
__u8 protocol;
|
||||
__u8 tunnelid;
|
||||
__u8 tunnelhdr;
|
||||
__u8 pad;
|
||||
};
|
||||
|
||||
/* ROUTE filter */
|
||||
|
||||
enum {
|
||||
@@ -234,6 +265,22 @@ enum {
|
||||
|
||||
#define TCA_FW_MAX (__TCA_FW_MAX - 1)
|
||||
|
||||
/* TC index filter */
|
||||
|
||||
enum {
|
||||
TCA_TCINDEX_UNSPEC,
|
||||
TCA_TCINDEX_HASH,
|
||||
TCA_TCINDEX_MASK,
|
||||
TCA_TCINDEX_SHIFT,
|
||||
TCA_TCINDEX_FALL_THROUGH,
|
||||
TCA_TCINDEX_CLASSID,
|
||||
TCA_TCINDEX_POLICE,
|
||||
TCA_TCINDEX_ACT,
|
||||
__TCA_TCINDEX_MAX
|
||||
};
|
||||
|
||||
#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
|
||||
|
||||
/* Flow filter */
|
||||
|
||||
enum {
|
||||
|
||||
@@ -457,6 +457,115 @@ enum {
|
||||
|
||||
#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1)
|
||||
|
||||
|
||||
/* CBQ section */
|
||||
|
||||
#define TC_CBQ_MAXPRIO 8
|
||||
#define TC_CBQ_MAXLEVEL 8
|
||||
#define TC_CBQ_DEF_EWMA 5
|
||||
|
||||
struct tc_cbq_lssopt {
|
||||
unsigned char change;
|
||||
unsigned char flags;
|
||||
#define TCF_CBQ_LSS_BOUNDED 1
|
||||
#define TCF_CBQ_LSS_ISOLATED 2
|
||||
unsigned char ewma_log;
|
||||
unsigned char level;
|
||||
#define TCF_CBQ_LSS_FLAGS 1
|
||||
#define TCF_CBQ_LSS_EWMA 2
|
||||
#define TCF_CBQ_LSS_MAXIDLE 4
|
||||
#define TCF_CBQ_LSS_MINIDLE 8
|
||||
#define TCF_CBQ_LSS_OFFTIME 0x10
|
||||
#define TCF_CBQ_LSS_AVPKT 0x20
|
||||
__u32 maxidle;
|
||||
__u32 minidle;
|
||||
__u32 offtime;
|
||||
__u32 avpkt;
|
||||
};
|
||||
|
||||
struct tc_cbq_wrropt {
|
||||
unsigned char flags;
|
||||
unsigned char priority;
|
||||
unsigned char cpriority;
|
||||
unsigned char __reserved;
|
||||
__u32 allot;
|
||||
__u32 weight;
|
||||
};
|
||||
|
||||
struct tc_cbq_ovl {
|
||||
unsigned char strategy;
|
||||
#define TC_CBQ_OVL_CLASSIC 0
|
||||
#define TC_CBQ_OVL_DELAY 1
|
||||
#define TC_CBQ_OVL_LOWPRIO 2
|
||||
#define TC_CBQ_OVL_DROP 3
|
||||
#define TC_CBQ_OVL_RCLASSIC 4
|
||||
unsigned char priority2;
|
||||
__u16 pad;
|
||||
__u32 penalty;
|
||||
};
|
||||
|
||||
struct tc_cbq_police {
|
||||
unsigned char police;
|
||||
unsigned char __res1;
|
||||
unsigned short __res2;
|
||||
};
|
||||
|
||||
struct tc_cbq_fopt {
|
||||
__u32 split;
|
||||
__u32 defmap;
|
||||
__u32 defchange;
|
||||
};
|
||||
|
||||
struct tc_cbq_xstats {
|
||||
__u32 borrows;
|
||||
__u32 overactions;
|
||||
__s32 avgidle;
|
||||
__s32 undertime;
|
||||
};
|
||||
|
||||
enum {
|
||||
TCA_CBQ_UNSPEC,
|
||||
TCA_CBQ_LSSOPT,
|
||||
TCA_CBQ_WRROPT,
|
||||
TCA_CBQ_FOPT,
|
||||
TCA_CBQ_OVL_STRATEGY,
|
||||
TCA_CBQ_RATE,
|
||||
TCA_CBQ_RTAB,
|
||||
TCA_CBQ_POLICE,
|
||||
__TCA_CBQ_MAX,
|
||||
};
|
||||
|
||||
#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1)
|
||||
|
||||
/* dsmark section */
|
||||
|
||||
enum {
|
||||
TCA_DSMARK_UNSPEC,
|
||||
TCA_DSMARK_INDICES,
|
||||
TCA_DSMARK_DEFAULT_INDEX,
|
||||
TCA_DSMARK_SET_TC_INDEX,
|
||||
TCA_DSMARK_MASK,
|
||||
TCA_DSMARK_VALUE,
|
||||
__TCA_DSMARK_MAX,
|
||||
};
|
||||
|
||||
#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1)
|
||||
|
||||
/* ATM section */
|
||||
|
||||
enum {
|
||||
TCA_ATM_UNSPEC,
|
||||
TCA_ATM_FD, /* file/socket descriptor */
|
||||
TCA_ATM_PTR, /* pointer to descriptor - later */
|
||||
TCA_ATM_HDR, /* LL header */
|
||||
TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */
|
||||
TCA_ATM_ADDR, /* PVC address (for output only) */
|
||||
TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */
|
||||
__TCA_ATM_MAX,
|
||||
};
|
||||
|
||||
#define TCA_ATM_MAX (__TCA_ATM_MAX - 1)
|
||||
|
||||
/* Network emulator */
|
||||
|
||||
enum {
|
||||
|
||||
@@ -41,7 +41,7 @@ fi
|
||||
# due to https://bugs.gentoo.org/794601) so let's just point the script to
|
||||
# commits referring to versions of libelf that actually can be built
|
||||
rm -rf elfutils
|
||||
git clone https://sourceware.org/git/elfutils.git
|
||||
git clone git://sourceware.org/git/elfutils.git
|
||||
(
|
||||
cd elfutils
|
||||
git checkout 67a187d4c1790058fc7fd218317851cb68bb087c
|
||||
|
||||
@@ -9,7 +9,7 @@ else
|
||||
endif
|
||||
|
||||
LIBBPF_MAJOR_VERSION := 1
|
||||
LIBBPF_MINOR_VERSION := 4
|
||||
LIBBPF_MINOR_VERSION := 3
|
||||
LIBBPF_PATCH_VERSION := 0
|
||||
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
||||
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
||||
@@ -35,10 +35,7 @@ ALL_CFLAGS := $(INCLUDES)
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
|
||||
ALL_CFLAGS += $(CFLAGS) \
|
||||
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
|
||||
-Wno-unknown-warning-option -Wno-format-overflow \
|
||||
$(EXTRA_CFLAGS)
|
||||
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(EXTRA_CFLAGS)
|
||||
ALL_LDFLAGS += $(LDFLAGS) $(EXTRA_LDFLAGS)
|
||||
|
||||
ifdef NO_PKG_CONFIG
|
||||
@@ -55,7 +52,7 @@ STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o \
|
||||
btf_dump.o hashmap.o ringbuf.o strset.o linker.o gen_loader.o \
|
||||
relo_core.o usdt.o zip.o elf.o features.o
|
||||
relo_core.o usdt.o zip.o
|
||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||
|
||||
|
||||
212
src/bpf.c
212
src/bpf.c
@@ -103,7 +103,7 @@ int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts)
|
||||
* [0] https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/
|
||||
* [1] d05512618056 ("bpf: Add bpf_ktime_get_coarse_ns helper")
|
||||
*/
|
||||
int probe_memcg_account(int token_fd)
|
||||
int probe_memcg_account(void)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd);
|
||||
struct bpf_insn insns[] = {
|
||||
@@ -120,9 +120,6 @@ int probe_memcg_account(int token_fd)
|
||||
attr.insns = ptr_to_u64(insns);
|
||||
attr.insn_cnt = insn_cnt;
|
||||
attr.license = ptr_to_u64("GPL");
|
||||
attr.prog_token_fd = token_fd;
|
||||
if (token_fd)
|
||||
attr.prog_flags |= BPF_F_TOKEN_FD;
|
||||
|
||||
prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, attr_sz);
|
||||
if (prog_fd >= 0) {
|
||||
@@ -149,7 +146,7 @@ int bump_rlimit_memlock(void)
|
||||
struct rlimit rlim;
|
||||
|
||||
/* if kernel supports memcg-based accounting, skip bumping RLIMIT_MEMLOCK */
|
||||
if (memlock_bumped || feat_supported(NULL, FEAT_MEMCG_ACCOUNT))
|
||||
if (memlock_bumped || kernel_supports(NULL, FEAT_MEMCG_ACCOUNT))
|
||||
return 0;
|
||||
|
||||
memlock_bumped = true;
|
||||
@@ -172,7 +169,7 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
__u32 max_entries,
|
||||
const struct bpf_map_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
@@ -184,7 +181,7 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
attr.map_type = map_type;
|
||||
if (map_name && feat_supported(NULL, FEAT_PROG_NAME))
|
||||
if (map_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||
libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
@@ -194,7 +191,6 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0);
|
||||
attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0);
|
||||
attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0);
|
||||
attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, 0);
|
||||
|
||||
attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
|
||||
attr.map_flags = OPTS_GET(opts, map_flags, 0);
|
||||
@@ -202,8 +198,6 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
attr.numa_node = OPTS_GET(opts, numa_node, 0);
|
||||
attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0);
|
||||
|
||||
attr.map_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
@@ -238,7 +232,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, log_true_size);
|
||||
void *finfo = NULL, *linfo = NULL;
|
||||
const char *func_info, *line_info;
|
||||
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
||||
@@ -267,9 +261,8 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
attr.prog_flags = OPTS_GET(opts, prog_flags, 0);
|
||||
attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0);
|
||||
attr.kern_version = OPTS_GET(opts, kern_version, 0);
|
||||
attr.prog_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
if (prog_name && feat_supported(NULL, FEAT_PROG_NAME))
|
||||
if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
|
||||
attr.license = ptr_to_u64(license);
|
||||
|
||||
@@ -636,89 +629,55 @@ int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
||||
return bpf_prog_attach_opts(prog_fd, target_fd, type, &opts);
|
||||
}
|
||||
|
||||
int bpf_prog_attach_opts(int prog_fd, int target, enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts)
|
||||
int bpf_prog_attach_opts(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
|
||||
__u32 relative_id, flags;
|
||||
int ret, relative_fd;
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
relative_id = OPTS_GET(opts, relative_id, 0);
|
||||
relative_fd = OPTS_GET(opts, relative_fd, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
/* validate we don't have unexpected combinations of non-zero fields */
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_fd, 0);
|
||||
attr.expected_revision = OPTS_GET(opts, expected_revision, 0);
|
||||
|
||||
if (relative_id) {
|
||||
attr.attach_flags = flags | BPF_F_ID;
|
||||
attr.relative_id = relative_id;
|
||||
} else {
|
||||
attr.attach_flags = flags;
|
||||
attr.relative_fd = relative_fd;
|
||||
}
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
||||
|
||||
ret = sys_bpf(BPF_PROG_ATTACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_prog_detach_opts(int prog_fd, int target, enum bpf_attach_type type,
|
||||
const struct bpf_prog_detach_opts *opts)
|
||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
|
||||
__u32 relative_id, flags;
|
||||
int ret, relative_fd;
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_prog_detach_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
relative_id = OPTS_GET(opts, relative_id, 0);
|
||||
relative_fd = OPTS_GET(opts, relative_fd, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
/* validate we don't have unexpected combinations of non-zero fields */
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.expected_revision = OPTS_GET(opts, expected_revision, 0);
|
||||
|
||||
if (relative_id) {
|
||||
attr.attach_flags = flags | BPF_F_ID;
|
||||
attr.relative_id = relative_id;
|
||||
} else {
|
||||
attr.attach_flags = flags;
|
||||
attr.relative_fd = relative_fd;
|
||||
}
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_type = type;
|
||||
|
||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
return bpf_prog_detach_opts(0, target_fd, type, NULL);
|
||||
}
|
||||
|
||||
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
return bpf_prog_detach_opts(prog_fd, target_fd, type, NULL);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
|
||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_link_create(int prog_fd, int target_fd,
|
||||
@@ -726,9 +685,9 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
const struct bpf_link_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, link_create);
|
||||
__u32 target_btf_id, iter_info_len, relative_id;
|
||||
int fd, err, relative_fd;
|
||||
__u32 target_btf_id, iter_info_len;
|
||||
union bpf_attr attr;
|
||||
int fd, err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_link_create_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
@@ -774,18 +733,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
if (!OPTS_ZEROED(opts, kprobe_multi))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TRACE_UPROBE_MULTI:
|
||||
attr.link_create.uprobe_multi.flags = OPTS_GET(opts, uprobe_multi.flags, 0);
|
||||
attr.link_create.uprobe_multi.cnt = OPTS_GET(opts, uprobe_multi.cnt, 0);
|
||||
attr.link_create.uprobe_multi.path = ptr_to_u64(OPTS_GET(opts, uprobe_multi.path, 0));
|
||||
attr.link_create.uprobe_multi.offsets = ptr_to_u64(OPTS_GET(opts, uprobe_multi.offsets, 0));
|
||||
attr.link_create.uprobe_multi.ref_ctr_offsets = ptr_to_u64(OPTS_GET(opts, uprobe_multi.ref_ctr_offsets, 0));
|
||||
attr.link_create.uprobe_multi.cookies = ptr_to_u64(OPTS_GET(opts, uprobe_multi.cookies, 0));
|
||||
attr.link_create.uprobe_multi.pid = OPTS_GET(opts, uprobe_multi.pid, 0);
|
||||
if (!OPTS_ZEROED(opts, uprobe_multi))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TRACE_RAW_TP:
|
||||
case BPF_TRACE_FENTRY:
|
||||
case BPF_TRACE_FEXIT:
|
||||
case BPF_MODIFY_RETURN:
|
||||
@@ -802,38 +749,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
if (!OPTS_ZEROED(opts, netfilter))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TCX_INGRESS:
|
||||
case BPF_TCX_EGRESS:
|
||||
relative_fd = OPTS_GET(opts, tcx.relative_fd, 0);
|
||||
relative_id = OPTS_GET(opts, tcx.relative_id, 0);
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (relative_id) {
|
||||
attr.link_create.tcx.relative_id = relative_id;
|
||||
attr.link_create.flags |= BPF_F_ID;
|
||||
} else {
|
||||
attr.link_create.tcx.relative_fd = relative_fd;
|
||||
}
|
||||
attr.link_create.tcx.expected_revision = OPTS_GET(opts, tcx.expected_revision, 0);
|
||||
if (!OPTS_ZEROED(opts, tcx))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_NETKIT_PRIMARY:
|
||||
case BPF_NETKIT_PEER:
|
||||
relative_fd = OPTS_GET(opts, netkit.relative_fd, 0);
|
||||
relative_id = OPTS_GET(opts, netkit.relative_id, 0);
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (relative_id) {
|
||||
attr.link_create.netkit.relative_id = relative_id;
|
||||
attr.link_create.flags |= BPF_F_ID;
|
||||
} else {
|
||||
attr.link_create.netkit.relative_fd = relative_fd;
|
||||
}
|
||||
attr.link_create.netkit.expected_revision = OPTS_GET(opts, netkit.expected_revision, 0);
|
||||
if (!OPTS_ZEROED(opts, netkit))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
default:
|
||||
if (!OPTS_ZEROED(opts, flags))
|
||||
return libbpf_err(-EINVAL);
|
||||
@@ -926,7 +841,8 @@ int bpf_iter_create(int link_fd)
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
int bpf_prog_query_opts(int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
struct bpf_prog_query_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, query);
|
||||
@@ -937,20 +853,18 @@ int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.query.target_fd = target;
|
||||
attr.query.attach_type = type;
|
||||
attr.query.query_flags = OPTS_GET(opts, query_flags, 0);
|
||||
attr.query.count = OPTS_GET(opts, count, 0);
|
||||
attr.query.prog_ids = ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
|
||||
attr.query.link_ids = ptr_to_u64(OPTS_GET(opts, link_ids, NULL));
|
||||
attr.query.prog_attach_flags = ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
|
||||
attr.query.link_attach_flags = ptr_to_u64(OPTS_GET(opts, link_attach_flags, NULL));
|
||||
|
||||
attr.query.target_fd = target_fd;
|
||||
attr.query.attach_type = type;
|
||||
attr.query.query_flags = OPTS_GET(opts, query_flags, 0);
|
||||
attr.query.prog_cnt = OPTS_GET(opts, prog_cnt, 0);
|
||||
attr.query.prog_ids = ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
|
||||
attr.query.prog_attach_flags = ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
|
||||
|
||||
ret = sys_bpf(BPF_PROG_QUERY, &attr, attr_sz);
|
||||
|
||||
OPTS_SET(opts, attach_flags, attr.query.attach_flags);
|
||||
OPTS_SET(opts, revision, attr.query.revision);
|
||||
OPTS_SET(opts, count, attr.query.count);
|
||||
OPTS_SET(opts, prog_cnt, attr.query.prog_cnt);
|
||||
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
@@ -1174,34 +1088,23 @@ int bpf_link_get_info_by_fd(int link_fd, struct bpf_link_info *info, __u32 *info
|
||||
return bpf_obj_get_info_by_fd(link_fd, info, info_len);
|
||||
}
|
||||
|
||||
int bpf_raw_tracepoint_open_opts(int prog_fd, struct bpf_raw_tp_opts *opts)
|
||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_raw_tp_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.raw_tracepoint.name = ptr_to_u64(name);
|
||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||
attr.raw_tracepoint.name = ptr_to_u64(OPTS_GET(opts, tp_name, NULL));
|
||||
attr.raw_tracepoint.cookie = OPTS_GET(opts, cookie, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_raw_tp_opts, opts, .tp_name = name);
|
||||
|
||||
return bpf_raw_tracepoint_open_opts(prog_fd, &opts);
|
||||
}
|
||||
|
||||
int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, btf_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, btf_log_true_size);
|
||||
union bpf_attr attr;
|
||||
char *log_buf;
|
||||
size_t log_size;
|
||||
@@ -1226,10 +1129,6 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts
|
||||
|
||||
attr.btf = ptr_to_u64(btf_data);
|
||||
attr.btf_size = btf_size;
|
||||
|
||||
attr.btf_flags = OPTS_GET(opts, btf_flags, 0);
|
||||
attr.btf_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
/* log_level == 0 and log_buf != NULL means "try loading without
|
||||
* log_buf, but retry with log_buf and log_level=1 on error", which is
|
||||
* consistent across low-level and high-level BTF and program loading
|
||||
@@ -1310,20 +1209,3 @@ int bpf_prog_bind_map(int prog_fd, int map_fd,
|
||||
ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, token_create);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_token_create_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.token_create.bpffs_fd = bpffs_fd;
|
||||
attr.token_create.flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_TOKEN_CREATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
201
src/bpf.h
201
src/bpf.h
@@ -35,7 +35,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBBPF_API int libbpf_set_memlock_rlim(size_t memlock_bytes);
|
||||
int libbpf_set_memlock_rlim(size_t memlock_bytes);
|
||||
|
||||
struct bpf_map_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -51,12 +51,8 @@ struct bpf_map_create_opts {
|
||||
|
||||
__u32 numa_node;
|
||||
__u32 map_ifindex;
|
||||
__s32 value_type_btf_obj_fd;
|
||||
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_map_create_opts__last_field token_fd
|
||||
#define bpf_map_create_opts__last_field map_ifindex
|
||||
|
||||
LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
@@ -106,10 +102,9 @@ struct bpf_prog_load_opts {
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_load_opts__last_field token_fd
|
||||
#define bpf_prog_load_opts__last_field log_true_size
|
||||
|
||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
@@ -135,12 +130,9 @@ struct bpf_btf_load_opts {
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
|
||||
__u32 btf_flags;
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_btf_load_opts__last_field token_fd
|
||||
#define bpf_btf_load_opts__last_field log_true_size
|
||||
|
||||
LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size,
|
||||
struct bpf_btf_load_opts *opts);
|
||||
@@ -190,14 +182,10 @@ LIBBPF_API int bpf_map_delete_batch(int fd, const void *keys,
|
||||
/**
|
||||
* @brief **bpf_map_lookup_batch()** allows for batch lookup of BPF map elements.
|
||||
*
|
||||
* The parameter *in_batch* is the address of the first element in the batch to
|
||||
* read. *out_batch* is an output parameter that should be passed as *in_batch*
|
||||
* to subsequent calls to **bpf_map_lookup_batch()**. NULL can be passed for
|
||||
* *in_batch* to indicate that the batched lookup starts from the beginning of
|
||||
* the map. Both *in_batch* and *out_batch* must point to memory large enough to
|
||||
* hold a single key, except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH,
|
||||
* LRU_HASH, LRU_PERCPU_HASH}**, for which the memory size must be at
|
||||
* least 4 bytes wide regardless of key size.
|
||||
* The parameter *in_batch* is the address of the first element in the batch to read.
|
||||
* *out_batch* is an output parameter that should be passed as *in_batch* to subsequent
|
||||
* calls to **bpf_map_lookup_batch()**. NULL can be passed for *in_batch* to indicate
|
||||
* that the batched lookup starts from the beginning of the map.
|
||||
*
|
||||
* The *keys* and *values* are output parameters which must point to memory large enough to
|
||||
* hold *count* items based on the key and value size of the map *map_fd*. The *keys*
|
||||
@@ -230,10 +218,7 @@ LIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch,
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param in_batch address of the first element in batch to read, can pass NULL to
|
||||
* get address of the first element in *out_batch*. If not NULL, must be large
|
||||
* enough to hold a key. For **BPF_MAP_TYPE_{HASH, PERCPU_HASH, LRU_HASH,
|
||||
* LRU_PERCPU_HASH}**, the memory size must be at least 4 bytes wide regardless
|
||||
* of key size.
|
||||
* get address of the first element in *out_batch*
|
||||
* @param out_batch output parameter that should be passed to next call as *in_batch*
|
||||
* @param keys pointer to an array of *count* keys
|
||||
* @param values pointer to an array large enough for *count* values
|
||||
@@ -327,68 +312,22 @@ LIBBPF_API int bpf_obj_get(const char *pathname);
|
||||
LIBBPF_API int bpf_obj_get_opts(const char *pathname,
|
||||
const struct bpf_obj_get_opts *opts);
|
||||
|
||||
struct bpf_prog_attach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
unsigned int flags;
|
||||
int replace_prog_fd;
|
||||
};
|
||||
#define bpf_prog_attach_opts__last_field replace_prog_fd
|
||||
|
||||
LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type, unsigned int flags);
|
||||
LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
struct bpf_prog_attach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
union {
|
||||
int replace_prog_fd;
|
||||
int replace_fd;
|
||||
};
|
||||
int relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_attach_opts__last_field expected_revision
|
||||
|
||||
struct bpf_prog_detach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
int relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_detach_opts__last_field expected_revision
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_attach_opts()** attaches the BPF program corresponding to
|
||||
* *prog_fd* to a *target* which can represent a file descriptor or netdevice
|
||||
* ifindex.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param target attach location file descriptor or ifindex
|
||||
* @param type attach type for the BPF program
|
||||
* @param opts options for configuring the attachment
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int target,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_detach_opts()** detaches the BPF program corresponding to
|
||||
* *prog_fd* from a *target* which can represent a file descriptor or netdevice
|
||||
* ifindex.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param target detach location file descriptor or ifindex
|
||||
* @param type detach type for the BPF program
|
||||
* @param opts options for configuring the detachment
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_detach_opts(int prog_fd, int target,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_detach_opts *opts);
|
||||
|
||||
union bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */
|
||||
struct bpf_link_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -407,15 +346,6 @@ struct bpf_link_create_opts {
|
||||
const unsigned long *addrs;
|
||||
const __u64 *cookies;
|
||||
} kprobe_multi;
|
||||
struct {
|
||||
__u32 flags;
|
||||
__u32 cnt;
|
||||
const char *path;
|
||||
const unsigned long *offsets;
|
||||
const unsigned long *ref_ctr_offsets;
|
||||
const __u64 *cookies;
|
||||
__u32 pid;
|
||||
} uprobe_multi;
|
||||
struct {
|
||||
__u64 cookie;
|
||||
} tracing;
|
||||
@@ -425,20 +355,10 @@ struct bpf_link_create_opts {
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
struct {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
} tcx;
|
||||
struct {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
} netkit;
|
||||
};
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_link_create_opts__last_field uprobe_multi.pid
|
||||
#define bpf_link_create_opts__last_field kprobe_multi.cookies
|
||||
|
||||
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type,
|
||||
@@ -507,10 +427,7 @@ LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);
|
||||
* program corresponding to *prog_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
* actual number of bytes written to *info*.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param info pointer to **struct bpf_prog_info** that will be populated with
|
||||
@@ -527,10 +444,7 @@ LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info,
|
||||
* map corresponding to *map_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
* actual number of bytes written to *info*.
|
||||
*
|
||||
* @param map_fd BPF map file descriptor
|
||||
* @param info pointer to **struct bpf_map_info** that will be populated with
|
||||
@@ -543,14 +457,11 @@ LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info,
|
||||
LIBBPF_API int bpf_map_get_info_by_fd(int map_fd, struct bpf_map_info *info, __u32 *info_len);
|
||||
|
||||
/**
|
||||
* @brief **bpf_btf_get_info_by_fd()** obtains information about the
|
||||
* @brief **bpf_btf_get_info_by_fd()** obtains information about the
|
||||
* BTF object corresponding to *btf_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
* actual number of bytes written to *info*.
|
||||
*
|
||||
* @param btf_fd BTF object file descriptor
|
||||
* @param info pointer to **struct bpf_btf_info** that will be populated with
|
||||
@@ -567,10 +478,7 @@ LIBBPF_API int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u
|
||||
* link corresponding to *link_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
* actual number of bytes written to *info*.
|
||||
*
|
||||
* @param link_fd BPF link file descriptor
|
||||
* @param info pointer to **struct bpf_link_info** that will be populated with
|
||||
@@ -587,45 +495,18 @@ struct bpf_prog_query_opts {
|
||||
__u32 query_flags;
|
||||
__u32 attach_flags; /* output argument */
|
||||
__u32 *prog_ids;
|
||||
union {
|
||||
/* input+output argument */
|
||||
__u32 prog_cnt;
|
||||
__u32 count;
|
||||
};
|
||||
__u32 prog_cnt; /* input+output argument */
|
||||
__u32 *prog_attach_flags;
|
||||
__u32 *link_ids;
|
||||
__u32 *link_attach_flags;
|
||||
__u64 revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_query_opts__last_field revision
|
||||
#define bpf_prog_query_opts__last_field prog_attach_flags
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_query_opts()** queries the BPF programs and BPF links
|
||||
* which are attached to *target* which can represent a file descriptor or
|
||||
* netdevice ifindex.
|
||||
*
|
||||
* @param target query location file descriptor or ifindex
|
||||
* @param type attach type for the BPF program
|
||||
* @param opts options for configuring the query
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
LIBBPF_API int bpf_prog_query_opts(int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
struct bpf_prog_query_opts *opts);
|
||||
LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type,
|
||||
__u32 query_flags, __u32 *attach_flags,
|
||||
__u32 *prog_ids, __u32 *prog_cnt);
|
||||
|
||||
struct bpf_raw_tp_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
const char *tp_name;
|
||||
__u64 cookie;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_raw_tp_opts__last_field cookie
|
||||
|
||||
LIBBPF_API int bpf_raw_tracepoint_open_opts(int prog_fd, struct bpf_raw_tp_opts *opts);
|
||||
LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd);
|
||||
LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
|
||||
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
|
||||
@@ -676,30 +557,6 @@ struct bpf_test_run_opts {
|
||||
LIBBPF_API int bpf_prog_test_run_opts(int prog_fd,
|
||||
struct bpf_test_run_opts *opts);
|
||||
|
||||
struct bpf_token_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_token_create_opts__last_field flags
|
||||
|
||||
/**
|
||||
* @brief **bpf_token_create()** creates a new instance of BPF token derived
|
||||
* from specified BPF FS mount point.
|
||||
*
|
||||
* BPF token created with this API can be passed to bpf() syscall for
|
||||
* commands like BPF_PROG_LOAD, BPF_MAP_CREATE, etc.
|
||||
*
|
||||
* @param bpffs_fd FD for BPF FS instance from which to derive a BPF token
|
||||
* instance.
|
||||
* @param opts optional BPF token creation options, can be NULL
|
||||
*
|
||||
* @return BPF token FD > 0, on success; negative error code, otherwise (errno
|
||||
* is also set to the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_token_create(int bpffs_fd,
|
||||
struct bpf_token_create_opts *opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#ifndef __BPF_CORE_READ_H__
|
||||
#define __BPF_CORE_READ_H__
|
||||
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
/*
|
||||
* enum bpf_field_info_kind is passed as a second argument into
|
||||
* __builtin_preserve_field_info() built-in to get a specific aspect of
|
||||
@@ -46,7 +44,7 @@ enum bpf_enum_value_kind {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||
bpf_probe_read_kernel( \
|
||||
(void *)dst, \
|
||||
(void *)dst, \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
#else
|
||||
@@ -113,61 +111,8 @@ enum bpf_enum_value_kind {
|
||||
val; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Write to a bitfield, identified by s->field.
|
||||
* This is the inverse of BPF_CORE_WRITE_BITFIELD().
|
||||
*/
|
||||
#define BPF_CORE_WRITE_BITFIELD(s, field, new_val) ({ \
|
||||
void *p = (void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
||||
unsigned int byte_size = __CORE_RELO(s, field, BYTE_SIZE); \
|
||||
unsigned int lshift = __CORE_RELO(s, field, LSHIFT_U64); \
|
||||
unsigned int rshift = __CORE_RELO(s, field, RSHIFT_U64); \
|
||||
unsigned long long mask, val, nval = new_val; \
|
||||
unsigned int rpad = rshift - lshift; \
|
||||
\
|
||||
asm volatile("" : "+r"(p)); \
|
||||
\
|
||||
switch (byte_size) { \
|
||||
case 1: val = *(unsigned char *)p; break; \
|
||||
case 2: val = *(unsigned short *)p; break; \
|
||||
case 4: val = *(unsigned int *)p; break; \
|
||||
case 8: val = *(unsigned long long *)p; break; \
|
||||
} \
|
||||
\
|
||||
mask = (~0ULL << rshift) >> lshift; \
|
||||
val = (val & ~mask) | ((nval << rpad) & mask); \
|
||||
\
|
||||
switch (byte_size) { \
|
||||
case 1: *(unsigned char *)p = val; break; \
|
||||
case 2: *(unsigned short *)p = val; break; \
|
||||
case 4: *(unsigned int *)p = val; break; \
|
||||
case 8: *(unsigned long long *)p = val; break; \
|
||||
} \
|
||||
})
|
||||
|
||||
/* Differentiator between compilers builtin implementations. This is a
|
||||
* requirement due to the compiler parsing differences where GCC optimizes
|
||||
* early in parsing those constructs of type pointers to the builtin specific
|
||||
* type, resulting in not being possible to collect the required type
|
||||
* information in the builtin expansion.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define ___bpf_typeof(type) ((typeof(type) *) 0)
|
||||
#else
|
||||
#define ___bpf_typeof1(type, NR) ({ \
|
||||
extern typeof(type) *___concat(bpf_type_tmp_, NR); \
|
||||
___concat(bpf_type_tmp_, NR); \
|
||||
})
|
||||
#define ___bpf_typeof(type) ___bpf_typeof1(type, __COUNTER__)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#define ___bpf_field_ref1(field) (field)
|
||||
#define ___bpf_field_ref2(type, field) (___bpf_typeof(type)->field)
|
||||
#else
|
||||
#define ___bpf_field_ref1(field) (&(field))
|
||||
#define ___bpf_field_ref2(type, field) (&(___bpf_typeof(type)->field))
|
||||
#endif
|
||||
#define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field)
|
||||
#define ___bpf_field_ref(args...) \
|
||||
___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args)
|
||||
|
||||
@@ -217,7 +162,7 @@ enum bpf_enum_value_kind {
|
||||
* BTF. Always succeeds.
|
||||
*/
|
||||
#define bpf_core_type_id_local(type) \
|
||||
__builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_LOCAL)
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)
|
||||
|
||||
/*
|
||||
* Convenience macro to get BTF type ID of a target kernel's type that matches
|
||||
@@ -227,7 +172,7 @@ enum bpf_enum_value_kind {
|
||||
* - 0, if no matching type was found in a target kernel BTF.
|
||||
*/
|
||||
#define bpf_core_type_id_kernel(type) \
|
||||
__builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_TARGET)
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided named type
|
||||
@@ -237,7 +182,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_exists(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_EXISTS)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided named type
|
||||
@@ -247,7 +192,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if the type does not match any in the target kernel
|
||||
*/
|
||||
#define bpf_core_type_matches(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_MATCHES)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES)
|
||||
|
||||
/*
|
||||
* Convenience macro to get the byte size of a provided named type
|
||||
@@ -257,7 +202,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_size(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_SIZE)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided enumerator value is defined in
|
||||
@@ -267,13 +212,8 @@ enum bpf_enum_value_kind {
|
||||
* kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define bpf_core_enum_value_exists(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)
|
||||
#else
|
||||
#define bpf_core_enum_value_exists(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_EXISTS)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convenience macro to get the integer value of an enumerator value in
|
||||
@@ -283,13 +223,8 @@ enum bpf_enum_value_kind {
|
||||
* present in target kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define bpf_core_enum_value(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)
|
||||
#else
|
||||
#define bpf_core_enum_value(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_VALUE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures
|
||||
@@ -301,7 +236,7 @@ enum bpf_enum_value_kind {
|
||||
* a relocation, which records BTF type ID describing root struct/union and an
|
||||
* accessor string which describes exact embedded field that was used to take
|
||||
* an address. See detailed description of this relocation format and
|
||||
* semantics in comments to struct bpf_core_relo in include/uapi/linux/bpf.h.
|
||||
* semantics in comments to struct bpf_field_reloc in libbpf_internal.h.
|
||||
*
|
||||
* This relocation allows libbpf to adjust BPF instruction to use correct
|
||||
* actual field offset, based on target kernel BTF type that matches original
|
||||
@@ -325,17 +260,6 @@ enum bpf_enum_value_kind {
|
||||
#define bpf_core_read_user_str(dst, sz, src) \
|
||||
bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak;
|
||||
|
||||
/*
|
||||
* Cast provided pointer *ptr* into a pointer to a specified *type* in such
|
||||
* a way that BPF verifier will become aware of associated kernel-side BTF
|
||||
* type. This allows to access members of kernel types directly without the
|
||||
* need to use BPF_CORE_READ() macros.
|
||||
*/
|
||||
#define bpf_core_cast(ptr, type) \
|
||||
((typeof(type) *)bpf_rdonly_cast((ptr), bpf_core_type_id_kernel(type)))
|
||||
|
||||
#define ___concat(a, b) a ## b
|
||||
#define ___apply(fn, n) ___concat(fn, n)
|
||||
#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@
|
||||
#define __uint(name, val) int (*name)[val]
|
||||
#define __type(name, val) typeof(val) *name
|
||||
#define __array(name, val) typeof(val) *name[]
|
||||
#define __ulong(name, val) enum { ___bpf_concat(__unique_value, __COUNTER__) = val } name
|
||||
|
||||
/*
|
||||
* Helper macro to place programs, maps, license in
|
||||
@@ -182,19 +181,12 @@ enum libbpf_tristate {
|
||||
#define __ksym __attribute__((section(".ksyms")))
|
||||
#define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
|
||||
#define __kptr __attribute__((btf_type_tag("kptr")))
|
||||
#define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr")))
|
||||
|
||||
#define bpf_ksym_exists(sym) ({ \
|
||||
_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \
|
||||
!!sym; \
|
||||
})
|
||||
|
||||
#define __arg_ctx __attribute__((btf_decl_tag("arg:ctx")))
|
||||
#define __arg_nonnull __attribute((btf_decl_tag("arg:nonnull")))
|
||||
#define __arg_nullable __attribute((btf_decl_tag("arg:nullable")))
|
||||
#define __arg_trusted __attribute((btf_decl_tag("arg:trusted")))
|
||||
#define __arg_arena __attribute((btf_decl_tag("arg:arena")))
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#ifndef __BPF_TRACING_H__
|
||||
#define __BPF_TRACING_H__
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
||||
#if defined(__TARGET_ARCH_x86)
|
||||
@@ -362,6 +362,8 @@ struct pt_regs___arm64 {
|
||||
#define __PT_PARM7_REG a6
|
||||
#define __PT_PARM8_REG a7
|
||||
|
||||
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
|
||||
203
src/btf.c
203
src/btf.c
@@ -448,165 +448,6 @@ static int btf_parse_type_sec(struct btf *btf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_validate_str(const struct btf *btf, __u32 str_off, const char *what, __u32 type_id)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s = btf__str_by_offset(btf, str_off);
|
||||
if (!s) {
|
||||
pr_warn("btf: type [%u]: invalid %s (string offset %u)\n", type_id, what, str_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_validate_id(const struct btf *btf, __u32 id, __u32 ctx_id)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
|
||||
t = btf__type_by_id(btf, id);
|
||||
if (!t) {
|
||||
pr_warn("btf: type [%u]: invalid referenced type ID %u\n", ctx_id, id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_validate_type(const struct btf *btf, const struct btf_type *t, __u32 id)
|
||||
{
|
||||
__u32 kind = btf_kind(t);
|
||||
int err, i, n;
|
||||
|
||||
err = btf_validate_str(btf, t->name_off, "type name", id);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (kind) {
|
||||
case BTF_KIND_UNKN:
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_FLOAT:
|
||||
break;
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
err = btf_validate_id(btf, t->type, id);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = btf_array(t);
|
||||
|
||||
err = btf_validate_id(btf, a->type, id);
|
||||
err = err ?: btf_validate_id(btf, a->index_type, id);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
const struct btf_member *m = btf_members(t);
|
||||
|
||||
n = btf_vlen(t);
|
||||
for (i = 0; i < n; i++, m++) {
|
||||
err = btf_validate_str(btf, m->name_off, "field name", id);
|
||||
err = err ?: btf_validate_id(btf, m->type, id);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_ENUM: {
|
||||
const struct btf_enum *m = btf_enum(t);
|
||||
|
||||
n = btf_vlen(t);
|
||||
for (i = 0; i < n; i++, m++) {
|
||||
err = btf_validate_str(btf, m->name_off, "enum name", id);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_ENUM64: {
|
||||
const struct btf_enum64 *m = btf_enum64(t);
|
||||
|
||||
n = btf_vlen(t);
|
||||
for (i = 0; i < n; i++, m++) {
|
||||
err = btf_validate_str(btf, m->name_off, "enum name", id);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_FUNC: {
|
||||
const struct btf_type *ft;
|
||||
|
||||
err = btf_validate_id(btf, t->type, id);
|
||||
if (err)
|
||||
return err;
|
||||
ft = btf__type_by_id(btf, t->type);
|
||||
if (btf_kind(ft) != BTF_KIND_FUNC_PROTO) {
|
||||
pr_warn("btf: type [%u]: referenced type [%u] is not FUNC_PROTO\n", id, t->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
const struct btf_param *m = btf_params(t);
|
||||
|
||||
n = btf_vlen(t);
|
||||
for (i = 0; i < n; i++, m++) {
|
||||
err = btf_validate_str(btf, m->name_off, "param name", id);
|
||||
err = err ?: btf_validate_id(btf, m->type, id);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_DATASEC: {
|
||||
const struct btf_var_secinfo *m = btf_var_secinfos(t);
|
||||
|
||||
n = btf_vlen(t);
|
||||
for (i = 0; i < n; i++, m++) {
|
||||
err = btf_validate_id(btf, m->type, id);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
pr_warn("btf: type [%u]: unrecognized kind %u\n", id, kind);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Validate basic sanity of BTF. It's intentionally less thorough than
|
||||
* kernel's validation and validates only properties of BTF that libbpf relies
|
||||
* on to be correct (e.g., valid type IDs, valid string offsets, etc)
|
||||
*/
|
||||
static int btf_sanity_check(const struct btf *btf)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
__u32 i, n = btf__type_cnt(btf);
|
||||
int err;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
t = btf_type_by_id(btf, i);
|
||||
err = btf_validate_type(btf, t, i);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u32 btf__type_cnt(const struct btf *btf)
|
||||
{
|
||||
return btf->start_id + btf->nr_types;
|
||||
@@ -1061,7 +902,6 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
|
||||
|
||||
err = btf_parse_str_sec(btf);
|
||||
err = err ?: btf_parse_type_sec(btf);
|
||||
err = err ?: btf_sanity_check(btf);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
@@ -1079,11 +919,6 @@ struct btf *btf__new(const void *data, __u32 size)
|
||||
return libbpf_ptr(btf_new(data, size, NULL));
|
||||
}
|
||||
|
||||
struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
|
||||
{
|
||||
return libbpf_ptr(btf_new(data, size, base_btf));
|
||||
}
|
||||
|
||||
static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
|
||||
struct btf_ext **btf_ext)
|
||||
{
|
||||
@@ -1322,9 +1157,7 @@ struct btf *btf__parse_split(const char *path, struct btf *base_btf)
|
||||
|
||||
static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
|
||||
|
||||
int btf_load_into_kernel(struct btf *btf,
|
||||
char *log_buf, size_t log_sz, __u32 log_level,
|
||||
int token_fd)
|
||||
int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_btf_load_opts, opts);
|
||||
__u32 buf_sz = 0, raw_size;
|
||||
@@ -1374,10 +1207,6 @@ retry_load:
|
||||
opts.log_level = log_level;
|
||||
}
|
||||
|
||||
opts.token_fd = token_fd;
|
||||
if (token_fd)
|
||||
opts.btf_flags |= BPF_F_TOKEN_FD;
|
||||
|
||||
btf->fd = bpf_btf_load(raw_data, raw_size, &opts);
|
||||
if (btf->fd < 0) {
|
||||
/* time to turn on verbose mode and try again */
|
||||
@@ -1405,7 +1234,7 @@ done:
|
||||
|
||||
int btf__load_into_kernel(struct btf *btf)
|
||||
{
|
||||
return btf_load_into_kernel(btf, NULL, 0, 0, 0);
|
||||
return btf_load_into_kernel(btf, NULL, 0, 0);
|
||||
}
|
||||
|
||||
int btf__fd(const struct btf *btf)
|
||||
@@ -3050,16 +2879,12 @@ done:
|
||||
return btf_ext;
|
||||
}
|
||||
|
||||
const void *btf_ext__raw_data(const struct btf_ext *btf_ext, __u32 *size)
|
||||
const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size)
|
||||
{
|
||||
*size = btf_ext->data_size;
|
||||
return btf_ext->data;
|
||||
}
|
||||
|
||||
__attribute__((alias("btf_ext__raw_data")))
|
||||
const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size);
|
||||
|
||||
|
||||
struct btf_dedup;
|
||||
|
||||
static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
@@ -4941,9 +4766,10 @@ static int btf_dedup_remap_types(struct btf_dedup *d)
|
||||
*/
|
||||
struct btf *btf__load_vmlinux_btf(void)
|
||||
{
|
||||
const char *sysfs_btf_path = "/sys/kernel/btf/vmlinux";
|
||||
/* fall back locations, trying to find vmlinux on disk */
|
||||
const char *locations[] = {
|
||||
/* try canonical vmlinux BTF through sysfs first */
|
||||
"/sys/kernel/btf/vmlinux",
|
||||
/* fall back to trying to find vmlinux on disk otherwise */
|
||||
"/boot/vmlinux-%1$s",
|
||||
"/lib/modules/%1$s/vmlinux-%1$s",
|
||||
"/lib/modules/%1$s/build/vmlinux",
|
||||
@@ -4957,23 +4783,8 @@ struct btf *btf__load_vmlinux_btf(void)
|
||||
struct btf *btf;
|
||||
int i, err;
|
||||
|
||||
/* is canonical sysfs location accessible? */
|
||||
if (faccessat(AT_FDCWD, sysfs_btf_path, F_OK, AT_EACCESS) < 0) {
|
||||
pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n",
|
||||
sysfs_btf_path);
|
||||
} else {
|
||||
btf = btf__parse(sysfs_btf_path, NULL);
|
||||
if (!btf) {
|
||||
err = -errno;
|
||||
pr_warn("failed to read kernel BTF from '%s': %d\n", sysfs_btf_path, err);
|
||||
return libbpf_err_ptr(err);
|
||||
}
|
||||
pr_debug("loaded kernel BTF from '%s'\n", sysfs_btf_path);
|
||||
return btf;
|
||||
}
|
||||
|
||||
/* try fallback locations */
|
||||
uname(&buf);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(locations); i++) {
|
||||
snprintf(path, PATH_MAX, locations[i], buf.release);
|
||||
|
||||
|
||||
558
src/elf.c
558
src/elf.c
@@ -1,558 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "libbpf_internal.h"
|
||||
#include "str_error.h"
|
||||
|
||||
/* A SHT_GNU_versym section holds 16-bit words. This bit is set if
|
||||
* the symbol is hidden and can only be seen when referenced using an
|
||||
* explicit version number. This is a GNU extension.
|
||||
*/
|
||||
#define VERSYM_HIDDEN 0x8000
|
||||
|
||||
/* This is the mask for the rest of the data in a word read from a
|
||||
* SHT_GNU_versym section.
|
||||
*/
|
||||
#define VERSYM_VERSION 0x7fff
|
||||
|
||||
int elf_open(const char *binary_path, struct elf_fd *elf_fd)
|
||||
{
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
int fd, ret;
|
||||
Elf *elf;
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||
pr_warn("elf: failed to init libelf for %s\n", binary_path);
|
||||
return -LIBBPF_ERRNO__LIBELF;
|
||||
}
|
||||
fd = open(binary_path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("elf: failed to open %s: %s\n", binary_path,
|
||||
libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
|
||||
return ret;
|
||||
}
|
||||
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!elf) {
|
||||
pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
close(fd);
|
||||
return -LIBBPF_ERRNO__FORMAT;
|
||||
}
|
||||
elf_fd->fd = fd;
|
||||
elf_fd->elf = elf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void elf_close(struct elf_fd *elf_fd)
|
||||
{
|
||||
if (!elf_fd)
|
||||
return;
|
||||
elf_end(elf_fd->elf);
|
||||
close(elf_fd->fd);
|
||||
}
|
||||
|
||||
/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
|
||||
static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
|
||||
{
|
||||
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||
GElf_Shdr sh;
|
||||
|
||||
if (!gelf_getshdr(scn, &sh))
|
||||
continue;
|
||||
if (sh.sh_type == sh_type)
|
||||
return scn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_sym {
|
||||
const char *name;
|
||||
GElf_Sym sym;
|
||||
GElf_Shdr sh;
|
||||
int ver;
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
struct elf_sym_iter {
|
||||
Elf *elf;
|
||||
Elf_Data *syms;
|
||||
Elf_Data *versyms;
|
||||
Elf_Data *verdefs;
|
||||
size_t nr_syms;
|
||||
size_t strtabidx;
|
||||
size_t verdef_strtabidx;
|
||||
size_t next_sym_idx;
|
||||
struct elf_sym sym;
|
||||
int st_type;
|
||||
};
|
||||
|
||||
static int elf_sym_iter_new(struct elf_sym_iter *iter,
|
||||
Elf *elf, const char *binary_path,
|
||||
int sh_type, int st_type)
|
||||
{
|
||||
Elf_Scn *scn = NULL;
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr sh;
|
||||
|
||||
memset(iter, 0, sizeof(*iter));
|
||||
|
||||
if (!gelf_getehdr(elf, &ehdr)) {
|
||||
pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, sh_type, NULL);
|
||||
if (!scn) {
|
||||
pr_debug("elf: failed to find symbol table ELF sections in '%s'\n",
|
||||
binary_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!gelf_getshdr(scn, &sh))
|
||||
return -EINVAL;
|
||||
|
||||
iter->strtabidx = sh.sh_link;
|
||||
iter->syms = elf_getdata(scn, 0);
|
||||
if (!iter->syms) {
|
||||
pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n",
|
||||
binary_path, elf_errmsg(-1));
|
||||
return -EINVAL;
|
||||
}
|
||||
iter->nr_syms = iter->syms->d_size / sh.sh_entsize;
|
||||
iter->elf = elf;
|
||||
iter->st_type = st_type;
|
||||
|
||||
/* Version symbol table is meaningful to dynsym only */
|
||||
if (sh_type != SHT_DYNSYM)
|
||||
return 0;
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, SHT_GNU_versym, NULL);
|
||||
if (!scn)
|
||||
return 0;
|
||||
iter->versyms = elf_getdata(scn, 0);
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, SHT_GNU_verdef, NULL);
|
||||
if (!scn)
|
||||
return 0;
|
||||
|
||||
iter->verdefs = elf_getdata(scn, 0);
|
||||
if (!iter->verdefs || !gelf_getshdr(scn, &sh)) {
|
||||
pr_warn("elf: failed to get verdef ELF section in '%s'\n", binary_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
iter->verdef_strtabidx = sh.sh_link;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct elf_sym *elf_sym_iter_next(struct elf_sym_iter *iter)
|
||||
{
|
||||
struct elf_sym *ret = &iter->sym;
|
||||
GElf_Sym *sym = &ret->sym;
|
||||
const char *name = NULL;
|
||||
GElf_Versym versym;
|
||||
Elf_Scn *sym_scn;
|
||||
size_t idx;
|
||||
|
||||
for (idx = iter->next_sym_idx; idx < iter->nr_syms; idx++) {
|
||||
if (!gelf_getsym(iter->syms, idx, sym))
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym->st_info) != iter->st_type)
|
||||
continue;
|
||||
name = elf_strptr(iter->elf, iter->strtabidx, sym->st_name);
|
||||
if (!name)
|
||||
continue;
|
||||
sym_scn = elf_getscn(iter->elf, sym->st_shndx);
|
||||
if (!sym_scn)
|
||||
continue;
|
||||
if (!gelf_getshdr(sym_scn, &ret->sh))
|
||||
continue;
|
||||
|
||||
iter->next_sym_idx = idx + 1;
|
||||
ret->name = name;
|
||||
ret->ver = 0;
|
||||
ret->hidden = false;
|
||||
|
||||
if (iter->versyms) {
|
||||
if (!gelf_getversym(iter->versyms, idx, &versym))
|
||||
continue;
|
||||
ret->ver = versym & VERSYM_VERSION;
|
||||
ret->hidden = versym & VERSYM_HIDDEN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *elf_get_vername(struct elf_sym_iter *iter, int ver)
|
||||
{
|
||||
GElf_Verdaux verdaux;
|
||||
GElf_Verdef verdef;
|
||||
int offset;
|
||||
|
||||
if (!iter->verdefs)
|
||||
return NULL;
|
||||
|
||||
offset = 0;
|
||||
while (gelf_getverdef(iter->verdefs, offset, &verdef)) {
|
||||
if (verdef.vd_ndx != ver) {
|
||||
if (!verdef.vd_next)
|
||||
break;
|
||||
|
||||
offset += verdef.vd_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!gelf_getverdaux(iter->verdefs, offset + verdef.vd_aux, &verdaux))
|
||||
break;
|
||||
|
||||
return elf_strptr(iter->elf, iter->verdef_strtabidx, verdaux.vda_name);
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool symbol_match(struct elf_sym_iter *iter, int sh_type, struct elf_sym *sym,
|
||||
const char *name, size_t name_len, const char *lib_ver)
|
||||
{
|
||||
const char *ver_name;
|
||||
|
||||
/* Symbols are in forms of func, func@LIB_VER or func@@LIB_VER
|
||||
* make sure the func part matches the user specified name
|
||||
*/
|
||||
if (strncmp(sym->name, name, name_len) != 0)
|
||||
return false;
|
||||
|
||||
/* ...but we don't want a search for "foo" to match 'foo2" also, so any
|
||||
* additional characters in sname should be of the form "@@LIB".
|
||||
*/
|
||||
if (sym->name[name_len] != '\0' && sym->name[name_len] != '@')
|
||||
return false;
|
||||
|
||||
/* If user does not specify symbol version, then we got a match */
|
||||
if (!lib_ver)
|
||||
return true;
|
||||
|
||||
/* If user specifies symbol version, for dynamic symbols,
|
||||
* get version name from ELF verdef section for comparison.
|
||||
*/
|
||||
if (sh_type == SHT_DYNSYM) {
|
||||
ver_name = elf_get_vername(iter, sym->ver);
|
||||
if (!ver_name)
|
||||
return false;
|
||||
return strcmp(ver_name, lib_ver) == 0;
|
||||
}
|
||||
|
||||
/* For normal symbols, it is already in form of func@LIB_VER */
|
||||
return strcmp(sym->name, name) == 0;
|
||||
}
|
||||
|
||||
/* Transform symbol's virtual address (absolute for binaries and relative
|
||||
* for shared libs) into file offset, which is what kernel is expecting
|
||||
* for uprobe/uretprobe attachment.
|
||||
* See Documentation/trace/uprobetracer.rst for more details. This is done
|
||||
* by looking up symbol's containing section's header and using iter's virtual
|
||||
* address (sh_addr) and corresponding file offset (sh_offset) to transform
|
||||
* sym.st_value (virtual address) into desired final file offset.
|
||||
*/
|
||||
static unsigned long elf_sym_offset(struct elf_sym *sym)
|
||||
{
|
||||
return sym->sym.st_value - sym->sh.sh_addr + sym->sh.sh_offset;
|
||||
}
|
||||
|
||||
/* Find offset of function name in the provided ELF object. "binary_path" is
|
||||
* the path to the ELF binary represented by "elf", and only used for error
|
||||
* reporting matters. "name" matches symbol name or name@@LIB for library
|
||||
* functions.
|
||||
*/
|
||||
long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name)
|
||||
{
|
||||
int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
|
||||
const char *at_symbol, *lib_ver;
|
||||
bool is_shared_lib;
|
||||
long ret = -ENOENT;
|
||||
size_t name_len;
|
||||
GElf_Ehdr ehdr;
|
||||
|
||||
if (!gelf_getehdr(elf, &ehdr)) {
|
||||
pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
ret = -LIBBPF_ERRNO__FORMAT;
|
||||
goto out;
|
||||
}
|
||||
/* for shared lib case, we do not need to calculate relative offset */
|
||||
is_shared_lib = ehdr.e_type == ET_DYN;
|
||||
|
||||
/* Does name specify "@@LIB_VER" or "@LIB_VER" ? */
|
||||
at_symbol = strchr(name, '@');
|
||||
if (at_symbol) {
|
||||
name_len = at_symbol - name;
|
||||
/* skip second @ if it's @@LIB_VER case */
|
||||
if (at_symbol[1] == '@')
|
||||
at_symbol++;
|
||||
lib_ver = at_symbol + 1;
|
||||
} else {
|
||||
name_len = strlen(name);
|
||||
lib_ver = NULL;
|
||||
}
|
||||
|
||||
/* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if
|
||||
* a binary is stripped, it may only have SHT_DYNSYM, and a fully-statically
|
||||
* linked binary may not have SHT_DYMSYM, so absence of a section should not be
|
||||
* reported as a warning/error.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
int last_bind = -1;
|
||||
int cur_bind;
|
||||
|
||||
ret = elf_sym_iter_new(&iter, elf, binary_path, sh_types[i], STT_FUNC);
|
||||
if (ret == -ENOENT)
|
||||
continue;
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
if (!symbol_match(&iter, sh_types[i], sym, name, name_len, lib_ver))
|
||||
continue;
|
||||
|
||||
cur_bind = GELF_ST_BIND(sym->sym.st_info);
|
||||
|
||||
if (ret > 0) {
|
||||
/* handle multiple matches */
|
||||
if (elf_sym_offset(sym) == ret) {
|
||||
/* same offset, no problem */
|
||||
continue;
|
||||
} else if (last_bind != STB_WEAK && cur_bind != STB_WEAK) {
|
||||
/* Only accept one non-weak bind. */
|
||||
pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n",
|
||||
sym->name, name, binary_path);
|
||||
ret = -LIBBPF_ERRNO__FORMAT;
|
||||
goto out;
|
||||
} else if (cur_bind == STB_WEAK) {
|
||||
/* already have a non-weak bind, and
|
||||
* this is a weak bind, so ignore.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret = elf_sym_offset(sym);
|
||||
last_bind = cur_bind;
|
||||
}
|
||||
if (ret > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
|
||||
ret);
|
||||
} else {
|
||||
if (ret == 0) {
|
||||
pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path,
|
||||
is_shared_lib ? "should not be 0 in a shared library" :
|
||||
"try using shared library path instead");
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find offset of function name in ELF object specified by path. "name" matches
|
||||
* symbol name or name@@LIB for library functions.
|
||||
*/
|
||||
long elf_find_func_offset_from_file(const char *binary_path, const char *name)
|
||||
{
|
||||
struct elf_fd elf_fd;
|
||||
long ret = -ENOENT;
|
||||
|
||||
ret = elf_open(binary_path, &elf_fd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = elf_find_func_offset(elf_fd.elf, binary_path, name);
|
||||
elf_close(&elf_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct symbol {
|
||||
const char *name;
|
||||
int bind;
|
||||
int idx;
|
||||
};
|
||||
|
||||
static int symbol_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct symbol *sym_a = a;
|
||||
const struct symbol *sym_b = b;
|
||||
|
||||
return strcmp(sym_a->name, sym_b->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offsets in @poffsets for symbols specified in @syms array argument.
|
||||
* On success returns 0 and offsets are returned in allocated array with @cnt
|
||||
* size, that needs to be released by the caller.
|
||||
*/
|
||||
int elf_resolve_syms_offsets(const char *binary_path, int cnt,
|
||||
const char **syms, unsigned long **poffsets,
|
||||
int st_type)
|
||||
{
|
||||
int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
|
||||
int err = 0, i, cnt_done = 0;
|
||||
unsigned long *offsets;
|
||||
struct symbol *symbols;
|
||||
struct elf_fd elf_fd;
|
||||
|
||||
err = elf_open(binary_path, &elf_fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
offsets = calloc(cnt, sizeof(*offsets));
|
||||
symbols = calloc(cnt, sizeof(*symbols));
|
||||
|
||||
if (!offsets || !symbols) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
symbols[i].name = syms[i];
|
||||
symbols[i].idx = i;
|
||||
}
|
||||
|
||||
qsort(symbols, cnt, sizeof(*symbols), symbol_cmp);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
|
||||
err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], st_type);
|
||||
if (err == -ENOENT)
|
||||
continue;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
unsigned long sym_offset = elf_sym_offset(sym);
|
||||
int bind = GELF_ST_BIND(sym->sym.st_info);
|
||||
struct symbol *found, tmp = {
|
||||
.name = sym->name,
|
||||
};
|
||||
unsigned long *offset;
|
||||
|
||||
found = bsearch(&tmp, symbols, cnt, sizeof(*symbols), symbol_cmp);
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
offset = &offsets[found->idx];
|
||||
if (*offset > 0) {
|
||||
/* same offset, no problem */
|
||||
if (*offset == sym_offset)
|
||||
continue;
|
||||
/* handle multiple matches */
|
||||
if (found->bind != STB_WEAK && bind != STB_WEAK) {
|
||||
/* Only accept one non-weak bind. */
|
||||
pr_warn("elf: ambiguous match found '%s@%lu' in '%s' previous offset %lu\n",
|
||||
sym->name, sym_offset, binary_path, *offset);
|
||||
err = -ESRCH;
|
||||
goto out;
|
||||
} else if (bind == STB_WEAK) {
|
||||
/* already have a non-weak bind, and
|
||||
* this is a weak bind, so ignore.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
cnt_done++;
|
||||
}
|
||||
*offset = sym_offset;
|
||||
found->bind = bind;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt != cnt_done) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*poffsets = offsets;
|
||||
|
||||
out:
|
||||
free(symbols);
|
||||
if (err)
|
||||
free(offsets);
|
||||
elf_close(&elf_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offsets in @poffsets for symbols specified by @pattern argument.
|
||||
* On success returns 0 and offsets are returned in allocated @poffsets
|
||||
* array with the @pctn size, that needs to be released by the caller.
|
||||
*/
|
||||
int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
|
||||
unsigned long **poffsets, size_t *pcnt)
|
||||
{
|
||||
int sh_types[2] = { SHT_SYMTAB, SHT_DYNSYM };
|
||||
unsigned long *offsets = NULL;
|
||||
size_t cap = 0, cnt = 0;
|
||||
struct elf_fd elf_fd;
|
||||
int err = 0, i;
|
||||
|
||||
err = elf_open(binary_path, &elf_fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
|
||||
err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC);
|
||||
if (err == -ENOENT)
|
||||
continue;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
if (!glob_match(sym->name, pattern))
|
||||
continue;
|
||||
|
||||
err = libbpf_ensure_mem((void **) &offsets, &cap, sizeof(*offsets),
|
||||
cnt + 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
offsets[cnt++] = elf_sym_offset(sym);
|
||||
}
|
||||
|
||||
/* If we found anything in the first symbol section,
|
||||
* do not search others to avoid duplicates.
|
||||
*/
|
||||
if (cnt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cnt) {
|
||||
*poffsets = offsets;
|
||||
*pcnt = cnt;
|
||||
} else {
|
||||
err = -ENOENT;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
free(offsets);
|
||||
elf_close(&elf_fd);
|
||||
return err;
|
||||
}
|
||||
583
src/features.c
583
src/features.c
@@ -1,583 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/filter.h>
|
||||
#include "bpf.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_common.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "str_error.h"
|
||||
|
||||
static inline __u64 ptr_to_u64(const void *ptr)
|
||||
{
|
||||
return (__u64)(unsigned long)ptr;
|
||||
}
|
||||
|
||||
int probe_fd(int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
static int probe_kern_prog_name(int token_fd)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, prog_name);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||
attr.license = ptr_to_u64("GPL");
|
||||
attr.insns = ptr_to_u64(insns);
|
||||
attr.insn_cnt = (__u32)ARRAY_SIZE(insns);
|
||||
attr.prog_token_fd = token_fd;
|
||||
if (token_fd)
|
||||
attr.prog_flags |= BPF_F_TOKEN_FD;
|
||||
libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name));
|
||||
|
||||
/* make sure loading with name works */
|
||||
ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_global_data(int token_fd)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||
.token_fd = token_fd,
|
||||
.map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, map, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts);
|
||||
if (map < 0) {
|
||||
ret = -errno;
|
||||
cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
|
||||
pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
|
||||
__func__, cp, -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
insns[0].imm = map;
|
||||
|
||||
ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
|
||||
close(map);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_btf(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_func(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int\0x\0a";
|
||||
/* void x(int a) {} */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* FUNC_PROTO */ /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
|
||||
BTF_PARAM_ENC(7, 1),
|
||||
/* FUNC x */ /* [3] */
|
||||
BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_func_global(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int\0x\0a";
|
||||
/* static void x(int a) {} */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* FUNC_PROTO */ /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
|
||||
BTF_PARAM_ENC(7, 1),
|
||||
/* FUNC x BTF_FUNC_GLOBAL */ /* [3] */
|
||||
BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_datasec(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0x\0.data";
|
||||
/* static int a; */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* DATASEC val */ /* [3] */
|
||||
BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_qmark_datasec(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0x\0?.data";
|
||||
/* static int a; */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* DATASEC ?.data */ /* [3] */
|
||||
BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_float(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0float";
|
||||
__u32 types[] = {
|
||||
/* float */
|
||||
BTF_TYPE_FLOAT_ENC(1, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_decl_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0tag";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* attr */
|
||||
BTF_TYPE_DECL_TAG_ENC(1, 2, -1),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_type_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0tag";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* attr */
|
||||
BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */
|
||||
/* ptr */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_array_mmap(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts,
|
||||
.map_flags = BPF_F_MMAPABLE | (token_fd ? BPF_F_TOKEN_FD : 0),
|
||||
.token_fd = token_fd,
|
||||
);
|
||||
int fd;
|
||||
|
||||
fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_kern_exp_attach_type(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
/* use any valid combination of program type and (optional)
|
||||
* non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS)
|
||||
* to see if kernel supports expected_attach_type field for
|
||||
* BPF_PROG_LOAD command
|
||||
*/
|
||||
fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_kern_probe_read_kernel(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */
|
||||
BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_prog_bind_map(int token_fd)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||
.token_fd = token_fd,
|
||||
.map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, map, prog, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts);
|
||||
if (map < 0) {
|
||||
ret = -errno;
|
||||
cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
|
||||
pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
|
||||
__func__, cp, -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
|
||||
if (prog < 0) {
|
||||
close(map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = bpf_prog_bind_map(prog, map, NULL);
|
||||
|
||||
close(map);
|
||||
close(prog);
|
||||
|
||||
return ret >= 0;
|
||||
}
|
||||
|
||||
static int probe_module_btf(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
|
||||
};
|
||||
struct bpf_btf_info info;
|
||||
__u32 len = sizeof(info);
|
||||
char name[16];
|
||||
int fd, err;
|
||||
|
||||
fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
|
||||
if (fd < 0)
|
||||
return 0; /* BTF not supported at all */
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.name = ptr_to_u64(name);
|
||||
info.name_len = sizeof(name);
|
||||
|
||||
/* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer;
|
||||
* kernel's module BTF support coincides with support for
|
||||
* name/name_len fields in struct bpf_btf_info.
|
||||
*/
|
||||
err = bpf_btf_get_info_by_fd(fd, &info, &len);
|
||||
close(fd);
|
||||
return !err;
|
||||
}
|
||||
|
||||
static int probe_perf_link(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int prog_fd, link_fd, err;
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL",
|
||||
insns, ARRAY_SIZE(insns), &opts);
|
||||
if (prog_fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* use invalid perf_event FD to get EBADF, if link is supported;
|
||||
* otherwise EINVAL should be returned
|
||||
*/
|
||||
link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL);
|
||||
err = -errno; /* close() can clobber errno */
|
||||
|
||||
if (link_fd >= 0)
|
||||
close(link_fd);
|
||||
close(prog_fd);
|
||||
|
||||
return link_fd < 0 && err == -EBADF;
|
||||
}
|
||||
|
||||
static int probe_uprobe_multi_link(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, load_opts,
|
||||
.expected_attach_type = BPF_TRACE_UPROBE_MULTI,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_link_create_opts, link_opts);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int prog_fd, link_fd, err;
|
||||
unsigned long offset = 0;
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL",
|
||||
insns, ARRAY_SIZE(insns), &load_opts);
|
||||
if (prog_fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* Creating uprobe in '/' binary should fail with -EBADF. */
|
||||
link_opts.uprobe_multi.path = "/";
|
||||
link_opts.uprobe_multi.offsets = &offset;
|
||||
link_opts.uprobe_multi.cnt = 1;
|
||||
|
||||
link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts);
|
||||
err = -errno; /* close() can clobber errno */
|
||||
|
||||
if (link_fd >= 0)
|
||||
close(link_fd);
|
||||
close(prog_fd);
|
||||
|
||||
return link_fd < 0 && err == -EBADF;
|
||||
}
|
||||
|
||||
static int probe_kern_bpf_cookie(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_btf_enum64(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0enum64";
|
||||
__u32 types[] = {
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_arg_ctx_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0a\0b\0arg:ctx\0";
|
||||
const __u32 types[] = {
|
||||
/* [1] INT */
|
||||
BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* [2] PTR -> VOID */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
|
||||
/* [3] FUNC_PROTO `int(void *a)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(1 /* "a" */, 2),
|
||||
/* [4] FUNC 'a' -> FUNC_PROTO (main prog) */
|
||||
BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3),
|
||||
/* [5] FUNC_PROTO `int(void *b __arg_ctx)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(3 /* "b" */, 2),
|
||||
/* [6] FUNC 'b' -> FUNC_PROTO (subprog) */
|
||||
BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5),
|
||||
/* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */
|
||||
BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0),
|
||||
};
|
||||
const struct bpf_insn insns[] = {
|
||||
/* main prog */
|
||||
BPF_CALL_REL(+1),
|
||||
BPF_EXIT_INSN(),
|
||||
/* global subprog */
|
||||
BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
const struct bpf_func_info_min func_infos[] = {
|
||||
{ 0, 4 }, /* main prog -> FUNC 'a' */
|
||||
{ 2, 6 }, /* subprog -> FUNC 'b' */
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
|
||||
if (btf_fd < 0)
|
||||
return 0;
|
||||
|
||||
opts.prog_btf_fd = btf_fd;
|
||||
opts.func_info = &func_infos;
|
||||
opts.func_info_cnt = ARRAY_SIZE(func_infos);
|
||||
opts.func_info_rec_size = sizeof(func_infos[0]);
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx",
|
||||
"GPL", insns, insn_cnt, &opts);
|
||||
close(btf_fd);
|
||||
|
||||
return probe_fd(prog_fd);
|
||||
}
|
||||
|
||||
typedef int (*feature_probe_fn)(int /* token_fd */);
|
||||
|
||||
static struct kern_feature_cache feature_cache;
|
||||
|
||||
static struct kern_feature_desc {
|
||||
const char *desc;
|
||||
feature_probe_fn probe;
|
||||
} feature_probes[__FEAT_CNT] = {
|
||||
[FEAT_PROG_NAME] = {
|
||||
"BPF program name", probe_kern_prog_name,
|
||||
},
|
||||
[FEAT_GLOBAL_DATA] = {
|
||||
"global variables", probe_kern_global_data,
|
||||
},
|
||||
[FEAT_BTF] = {
|
||||
"minimal BTF", probe_kern_btf,
|
||||
},
|
||||
[FEAT_BTF_FUNC] = {
|
||||
"BTF functions", probe_kern_btf_func,
|
||||
},
|
||||
[FEAT_BTF_GLOBAL_FUNC] = {
|
||||
"BTF global function", probe_kern_btf_func_global,
|
||||
},
|
||||
[FEAT_BTF_DATASEC] = {
|
||||
"BTF data section and variable", probe_kern_btf_datasec,
|
||||
},
|
||||
[FEAT_ARRAY_MMAP] = {
|
||||
"ARRAY map mmap()", probe_kern_array_mmap,
|
||||
},
|
||||
[FEAT_EXP_ATTACH_TYPE] = {
|
||||
"BPF_PROG_LOAD expected_attach_type attribute",
|
||||
probe_kern_exp_attach_type,
|
||||
},
|
||||
[FEAT_PROBE_READ_KERN] = {
|
||||
"bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel,
|
||||
},
|
||||
[FEAT_PROG_BIND_MAP] = {
|
||||
"BPF_PROG_BIND_MAP support", probe_prog_bind_map,
|
||||
},
|
||||
[FEAT_MODULE_BTF] = {
|
||||
"module BTF support", probe_module_btf,
|
||||
},
|
||||
[FEAT_BTF_FLOAT] = {
|
||||
"BTF_KIND_FLOAT support", probe_kern_btf_float,
|
||||
},
|
||||
[FEAT_PERF_LINK] = {
|
||||
"BPF perf link support", probe_perf_link,
|
||||
},
|
||||
[FEAT_BTF_DECL_TAG] = {
|
||||
"BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag,
|
||||
},
|
||||
[FEAT_BTF_TYPE_TAG] = {
|
||||
"BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag,
|
||||
},
|
||||
[FEAT_MEMCG_ACCOUNT] = {
|
||||
"memcg-based memory accounting", probe_memcg_account,
|
||||
},
|
||||
[FEAT_BPF_COOKIE] = {
|
||||
"BPF cookie support", probe_kern_bpf_cookie,
|
||||
},
|
||||
[FEAT_BTF_ENUM64] = {
|
||||
"BTF_KIND_ENUM64 support", probe_kern_btf_enum64,
|
||||
},
|
||||
[FEAT_SYSCALL_WRAPPER] = {
|
||||
"Kernel using syscall wrapper", probe_kern_syscall_wrapper,
|
||||
},
|
||||
[FEAT_UPROBE_MULTI_LINK] = {
|
||||
"BPF multi-uprobe link support", probe_uprobe_multi_link,
|
||||
},
|
||||
[FEAT_ARG_CTX_TAG] = {
|
||||
"kernel-side __arg_ctx tag", probe_kern_arg_ctx_tag,
|
||||
},
|
||||
[FEAT_BTF_QMARK_DATASEC] = {
|
||||
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
|
||||
},
|
||||
};
|
||||
|
||||
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
|
||||
{
|
||||
struct kern_feature_desc *feat = &feature_probes[feat_id];
|
||||
int ret;
|
||||
|
||||
/* assume global feature cache, unless custom one is provided */
|
||||
if (!cache)
|
||||
cache = &feature_cache;
|
||||
|
||||
if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
|
||||
ret = feat->probe(cache->token_fd);
|
||||
if (ret > 0) {
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED);
|
||||
} else if (ret == 0) {
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
|
||||
} else {
|
||||
pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret);
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
|
||||
}
|
||||
}
|
||||
|
||||
return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
|
||||
}
|
||||
@@ -80,6 +80,16 @@ struct hashmap {
|
||||
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,
|
||||
hashmap_equal_fn equal_fn, void *ctx);
|
||||
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
||||
|
||||
2356
src/libbpf.c
2356
src/libbpf.c
File diff suppressed because it is too large
Load Diff
192
src/libbpf.h
192
src/libbpf.h
@@ -177,29 +177,10 @@ struct bpf_object_open_opts {
|
||||
* logs through its print callback.
|
||||
*/
|
||||
__u32 kernel_log_level;
|
||||
/* Path to BPF FS mount point to derive BPF token from.
|
||||
*
|
||||
* Created BPF token will be used for all bpf() syscall operations
|
||||
* that accept BPF token (e.g., map creation, BTF and program loads,
|
||||
* etc) automatically within instantiated BPF object.
|
||||
*
|
||||
* If bpf_token_path is not specified, libbpf will consult
|
||||
* LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will be
|
||||
* taken as a value of bpf_token_path option and will force libbpf to
|
||||
* either create BPF token from provided custom BPF FS path, or will
|
||||
* disable implicit BPF token creation, if envvar value is an empty
|
||||
* string. bpf_token_path overrides LIBBPF_BPF_TOKEN_PATH, if both are
|
||||
* set at the same time.
|
||||
*
|
||||
* Setting bpf_token_path option to empty string disables libbpf's
|
||||
* automatic attempt to create BPF token from default BPF FS mount
|
||||
* point (/sys/fs/bpf), in case this default behavior is undesirable.
|
||||
*/
|
||||
const char *bpf_token_path;
|
||||
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_object_open_opts__last_field bpf_token_path
|
||||
#define bpf_object_open_opts__last_field kernel_log_level
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__open()** creates a bpf_object by opening
|
||||
@@ -285,7 +266,6 @@ LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||
LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
||||
LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path);
|
||||
|
||||
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
||||
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
||||
@@ -549,57 +529,6 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
||||
const char *pattern,
|
||||
const struct bpf_kprobe_multi_opts *opts);
|
||||
|
||||
struct bpf_uprobe_multi_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
/* array of function symbols to attach to */
|
||||
const char **syms;
|
||||
/* array of function addresses to attach to */
|
||||
const unsigned long *offsets;
|
||||
/* optional, array of associated ref counter offsets */
|
||||
const unsigned long *ref_ctr_offsets;
|
||||
/* optional, array of associated BPF cookies */
|
||||
const __u64 *cookies;
|
||||
/* number of elements in syms/addrs/cookies arrays */
|
||||
size_t cnt;
|
||||
/* create return uprobes */
|
||||
bool retprobe;
|
||||
size_t :0;
|
||||
};
|
||||
|
||||
#define bpf_uprobe_multi_opts__last_field retprobe
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program
|
||||
* to multiple uprobes with uprobe_multi link.
|
||||
*
|
||||
* User can specify 2 mutually exclusive set of inputs:
|
||||
*
|
||||
* 1) use only path/func_pattern/pid arguments
|
||||
*
|
||||
* 2) use path/pid with allowed combinations of
|
||||
* syms/offsets/ref_ctr_offsets/cookies/cnt
|
||||
*
|
||||
* - syms and offsets are mutually exclusive
|
||||
* - ref_ctr_offsets and cookies are optional
|
||||
*
|
||||
*
|
||||
* @param prog BPF program to attach
|
||||
* @param pid Process ID to attach the uprobe to, 0 for self (own process),
|
||||
* -1 for all processes
|
||||
* @param binary_path Path to binary
|
||||
* @param func_pattern Regular expression to specify functions to attach
|
||||
* BPF program to
|
||||
* @param opts Additional options (see **struct bpf_uprobe_multi_opts**)
|
||||
* @return 0, on success; negative error code, otherwise
|
||||
*/
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
|
||||
pid_t pid,
|
||||
const char *binary_path,
|
||||
const char *func_pattern,
|
||||
const struct bpf_uprobe_multi_opts *opts);
|
||||
|
||||
struct bpf_ksyscall_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
@@ -760,20 +689,9 @@ bpf_program__attach_tracepoint_opts(const struct bpf_program *prog,
|
||||
const char *tp_name,
|
||||
const struct bpf_tracepoint_opts *opts);
|
||||
|
||||
struct bpf_raw_tracepoint_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u64 cookie;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_raw_tracepoint_opts__last_field cookie
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_raw_tracepoint(const struct bpf_program *prog,
|
||||
const char *tp_name);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog,
|
||||
const char *tp_name,
|
||||
struct bpf_raw_tracepoint_opts *opts);
|
||||
|
||||
struct bpf_trace_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
@@ -815,36 +733,6 @@ LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_netfilter(const struct bpf_program *prog,
|
||||
const struct bpf_netfilter_opts *opts);
|
||||
|
||||
struct bpf_tcx_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
__u32 flags;
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_tcx_opts__last_field expected_revision
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_tcx(const struct bpf_program *prog, int ifindex,
|
||||
const struct bpf_tcx_opts *opts);
|
||||
|
||||
struct bpf_netkit_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
__u32 flags;
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_netkit_opts__last_field expected_revision
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_netkit(const struct bpf_program *prog, int ifindex,
|
||||
const struct bpf_netkit_opts *opts);
|
||||
|
||||
struct bpf_map;
|
||||
|
||||
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
||||
@@ -1025,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,
|
||||
const void *data, size_t size);
|
||||
LIBBPF_API void *bpf_map__initial_value(const 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
|
||||
@@ -1217,10 +1105,9 @@ struct bpf_xdp_query_opts {
|
||||
__u32 skb_prog_id; /* output */
|
||||
__u8 attach_mode; /* output */
|
||||
__u64 feature_flags; /* output */
|
||||
__u32 xdp_zc_max_segs; /* output */
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_xdp_query_opts__last_field xdp_zc_max_segs
|
||||
#define bpf_xdp_query_opts__last_field feature_flags
|
||||
|
||||
LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags,
|
||||
const struct bpf_xdp_attach_opts *opts);
|
||||
@@ -1274,7 +1161,6 @@ LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,
|
||||
|
||||
/* Ring buffer APIs */
|
||||
struct ring_buffer;
|
||||
struct ring;
|
||||
struct user_ring_buffer;
|
||||
|
||||
typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);
|
||||
@@ -1295,78 +1181,6 @@ LIBBPF_API int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms);
|
||||
LIBBPF_API int ring_buffer__consume(struct ring_buffer *rb);
|
||||
LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);
|
||||
|
||||
/**
|
||||
* @brief **ring_buffer__ring()** returns the ringbuffer object inside a given
|
||||
* ringbuffer manager representing a single BPF_MAP_TYPE_RINGBUF map instance.
|
||||
*
|
||||
* @param rb A ringbuffer manager object.
|
||||
* @param idx An index into the ringbuffers contained within the ringbuffer
|
||||
* manager object. The index is 0-based and corresponds to the order in which
|
||||
* ring_buffer__add was called.
|
||||
* @return A ringbuffer object on success; NULL and errno set if the index is
|
||||
* invalid.
|
||||
*/
|
||||
LIBBPF_API struct ring *ring_buffer__ring(struct ring_buffer *rb,
|
||||
unsigned int idx);
|
||||
|
||||
/**
|
||||
* @brief **ring__consumer_pos()** returns the current consumer position in the
|
||||
* given ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The current consumer position.
|
||||
*/
|
||||
LIBBPF_API unsigned long ring__consumer_pos(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__producer_pos()** returns the current producer position in the
|
||||
* given ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The current producer position.
|
||||
*/
|
||||
LIBBPF_API unsigned long ring__producer_pos(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__avail_data_size()** returns the number of bytes in the
|
||||
* ringbuffer not yet consumed. This has no locking associated with it, so it
|
||||
* can be inaccurate if operations are ongoing while this is called. However, it
|
||||
* should still show the correct trend over the long-term.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The number of bytes not yet consumed.
|
||||
*/
|
||||
LIBBPF_API size_t ring__avail_data_size(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__size()** returns the total size of the ringbuffer's map data
|
||||
* area (excluding special producer/consumer pages). Effectively this gives the
|
||||
* amount of usable bytes of data inside the ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The total size of the ringbuffer map data area.
|
||||
*/
|
||||
LIBBPF_API size_t ring__size(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__map_fd()** returns the file descriptor underlying the given
|
||||
* ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The underlying ringbuffer file descriptor
|
||||
*/
|
||||
LIBBPF_API int ring__map_fd(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__consume()** consumes available ringbuffer data without event
|
||||
* polling.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The number of records consumed (or INT_MAX, whichever is less), or
|
||||
* a negative number if any of the callbacks return an error.
|
||||
*/
|
||||
LIBBPF_API int ring__consume(struct ring *r);
|
||||
|
||||
struct user_ring_buffer_opts {
|
||||
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||
};
|
||||
|
||||
@@ -245,6 +245,7 @@ LIBBPF_0.3.0 {
|
||||
btf__parse_raw_split;
|
||||
btf__parse_split;
|
||||
btf__new_empty_split;
|
||||
btf__new_split;
|
||||
ring_buffer__epoll_fd;
|
||||
} LIBBPF_0.2.0;
|
||||
|
||||
@@ -325,6 +326,7 @@ LIBBPF_0.7.0 {
|
||||
bpf_xdp_detach;
|
||||
bpf_xdp_query;
|
||||
bpf_xdp_query_id;
|
||||
btf_ext__raw_data;
|
||||
libbpf_probe_bpf_helper;
|
||||
libbpf_probe_bpf_map_type;
|
||||
libbpf_probe_bpf_prog_type;
|
||||
@@ -393,26 +395,5 @@ LIBBPF_1.2.0 {
|
||||
LIBBPF_1.3.0 {
|
||||
global:
|
||||
bpf_obj_pin_opts;
|
||||
bpf_object__unpin;
|
||||
bpf_prog_detach_opts;
|
||||
bpf_program__attach_netfilter;
|
||||
bpf_program__attach_netkit;
|
||||
bpf_program__attach_tcx;
|
||||
bpf_program__attach_uprobe_multi;
|
||||
ring__avail_data_size;
|
||||
ring__consume;
|
||||
ring__consumer_pos;
|
||||
ring__map_fd;
|
||||
ring__producer_pos;
|
||||
ring__size;
|
||||
ring_buffer__ring;
|
||||
} LIBBPF_1.2.0;
|
||||
|
||||
LIBBPF_1.4.0 {
|
||||
global:
|
||||
bpf_program__attach_raw_tracepoint_opts;
|
||||
bpf_raw_tracepoint_open_opts;
|
||||
bpf_token_create;
|
||||
btf__new_split;
|
||||
btf_ext__raw_data;
|
||||
} LIBBPF_1.3.0;
|
||||
|
||||
@@ -70,23 +70,4 @@
|
||||
}; \
|
||||
})
|
||||
|
||||
/* Helper macro to clear and optionally reinitialize libbpf options struct
|
||||
*
|
||||
* Small helper macro to reset all fields and to reinitialize the common
|
||||
* structure size member. Values provided by users in struct initializer-
|
||||
* syntax as varargs can be provided as well to reinitialize options struct
|
||||
* specific members.
|
||||
*/
|
||||
#define LIBBPF_OPTS_RESET(NAME, ...) \
|
||||
do { \
|
||||
typeof(NAME) ___##NAME = ({ \
|
||||
memset(&___##NAME, 0, sizeof(NAME)); \
|
||||
(typeof(NAME)) { \
|
||||
.sz = sizeof(NAME), \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
}); \
|
||||
memcpy(&NAME, &___##NAME, sizeof(NAME)); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_COMMON_H */
|
||||
|
||||
@@ -15,24 +15,8 @@
|
||||
#include <linux/err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <libelf.h>
|
||||
#include "relo_core.h"
|
||||
|
||||
/* Android's libc doesn't support AT_EACCESS in faccessat() implementation
|
||||
* ([0]), and just returns -EINVAL even if file exists and is accessible.
|
||||
* See [1] for issues caused by this.
|
||||
*
|
||||
* So just redefine it to 0 on Android.
|
||||
*
|
||||
* [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50
|
||||
* [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250
|
||||
*/
|
||||
#ifdef __ANDROID__
|
||||
#undef AT_EACCESS
|
||||
#define AT_EACCESS 0
|
||||
#endif
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
@@ -370,41 +354,18 @@ enum kern_feature_id {
|
||||
FEAT_BTF_ENUM64,
|
||||
/* Kernel uses syscall wrapper (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) */
|
||||
FEAT_SYSCALL_WRAPPER,
|
||||
/* BPF multi-uprobe link support */
|
||||
FEAT_UPROBE_MULTI_LINK,
|
||||
/* Kernel supports arg:ctx tag (__arg_ctx) for global subprogs natively */
|
||||
FEAT_ARG_CTX_TAG,
|
||||
/* Kernel supports '?' at the front of datasec names */
|
||||
FEAT_BTF_QMARK_DATASEC,
|
||||
__FEAT_CNT,
|
||||
};
|
||||
|
||||
enum kern_feature_result {
|
||||
FEAT_UNKNOWN = 0,
|
||||
FEAT_SUPPORTED = 1,
|
||||
FEAT_MISSING = 2,
|
||||
};
|
||||
|
||||
struct kern_feature_cache {
|
||||
enum kern_feature_result res[__FEAT_CNT];
|
||||
int token_fd;
|
||||
};
|
||||
|
||||
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
|
||||
int probe_memcg_account(void);
|
||||
bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
|
||||
|
||||
int probe_kern_syscall_wrapper(int token_fd);
|
||||
int probe_memcg_account(int token_fd);
|
||||
int bump_rlimit_memlock(void);
|
||||
|
||||
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
||||
int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len,
|
||||
int token_fd);
|
||||
int btf_load_into_kernel(struct btf *btf,
|
||||
char *log_buf, size_t log_sz, __u32 log_level,
|
||||
int token_fd);
|
||||
const char *str_sec, size_t str_len);
|
||||
int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level);
|
||||
|
||||
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
||||
void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
|
||||
@@ -568,17 +529,6 @@ static inline bool is_ldimm64_insn(struct bpf_insn *insn)
|
||||
return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
||||
}
|
||||
|
||||
/* Unconditionally dup FD, ensuring it doesn't use [0, 2] range.
|
||||
* Original FD is not closed or altered in any other way.
|
||||
* Preserves original FD value, if it's invalid (negative).
|
||||
*/
|
||||
static inline int dup_good_fd(int fd)
|
||||
{
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
return fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
}
|
||||
|
||||
/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2
|
||||
* Takes ownership of the fd passed in, and closes it if calling
|
||||
* fcntl(fd, F_DUPFD_CLOEXEC, 3).
|
||||
@@ -590,7 +540,7 @@ static inline int ensure_good_fd(int fd)
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
if (fd < 3) {
|
||||
fd = dup_good_fd(fd);
|
||||
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
saved_errno = errno;
|
||||
close(old_fd);
|
||||
errno = saved_errno;
|
||||
@@ -602,29 +552,6 @@ static inline int ensure_good_fd(int fd)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline int sys_dup2(int oldfd, int newfd)
|
||||
{
|
||||
#ifdef __NR_dup2
|
||||
return syscall(__NR_dup2, oldfd, newfd);
|
||||
#else
|
||||
return syscall(__NR_dup3, oldfd, newfd, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Point *fixed_fd* to the same file that *tmp_fd* points to.
|
||||
* Regardless of success, *tmp_fd* is closed.
|
||||
* Whatever *fixed_fd* pointed to is closed silently.
|
||||
*/
|
||||
static inline int reuse_fd(int fixed_fd, int tmp_fd)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = sys_dup2(tmp_fd, fixed_fd);
|
||||
err = err < 0 ? -errno : 0;
|
||||
close(tmp_fd); /* clean up temporary FD */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The following two functions are exposed to bpftool */
|
||||
int bpf_core_add_cands(struct bpf_core_cand *local_cand,
|
||||
size_t local_essent_len,
|
||||
@@ -650,25 +577,4 @@ static inline bool is_pow_of_2(size_t x)
|
||||
#define PROG_LOAD_ATTEMPTS 5
|
||||
int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts);
|
||||
|
||||
bool glob_match(const char *str, const char *pat);
|
||||
|
||||
long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
|
||||
long elf_find_func_offset_from_file(const char *binary_path, const char *name);
|
||||
|
||||
struct elf_fd {
|
||||
Elf *elf;
|
||||
int fd;
|
||||
};
|
||||
|
||||
int elf_open(const char *binary_path, struct elf_fd *elf_fd);
|
||||
void elf_close(struct elf_fd *elf_fd);
|
||||
|
||||
int elf_resolve_syms_offsets(const char *binary_path, int cnt,
|
||||
const char **syms, unsigned long **poffsets,
|
||||
int st_type);
|
||||
int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
|
||||
unsigned long **poffsets, size_t *pcnt);
|
||||
|
||||
int probe_fd(int fd);
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||
|
||||
@@ -74,6 +74,10 @@ static __u32 get_debian_kernel_version(struct utsname *info)
|
||||
if (sscanf(p, "Debian %u.%u.%u", &major, &minor, &patch) != 3)
|
||||
return 0;
|
||||
|
||||
// Patch to run on Debian 10
|
||||
if (major == 4 && minor == 19)
|
||||
return KERNEL_VERSION(major, minor, 255);
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
@@ -97,9 +101,6 @@ __u32 get_kernel_version(void)
|
||||
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
|
||||
return 0;
|
||||
|
||||
if (major == 4 && minor == 19 && patch > 255)
|
||||
return KERNEL_VERSION(major, minor, 255);
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
@@ -222,8 +223,7 @@ int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts)
|
||||
}
|
||||
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len,
|
||||
int token_fd)
|
||||
const char *str_sec, size_t str_len)
|
||||
{
|
||||
struct btf_header hdr = {
|
||||
.magic = BTF_MAGIC,
|
||||
@@ -233,10 +233,6 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
.str_off = types_len,
|
||||
.str_len = str_len,
|
||||
};
|
||||
LIBBPF_OPTS(bpf_btf_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.btf_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int btf_fd, btf_len;
|
||||
__u8 *raw_btf;
|
||||
|
||||
@@ -249,7 +245,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
|
||||
memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
|
||||
|
||||
btf_fd = bpf_btf_load(raw_btf, btf_len, &opts);
|
||||
btf_fd = bpf_btf_load(raw_btf, btf_len, NULL);
|
||||
|
||||
free(raw_btf);
|
||||
return btf_fd;
|
||||
@@ -279,7 +275,7 @@ static int load_local_storage_btf(void)
|
||||
};
|
||||
|
||||
return libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), 0);
|
||||
strs, sizeof(strs));
|
||||
}
|
||||
|
||||
static int probe_map_create(enum bpf_map_type map_type)
|
||||
@@ -334,20 +330,12 @@ static int probe_map_create(enum bpf_map_type map_type)
|
||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
||||
opts.btf_vmlinux_value_type_id = 1;
|
||||
opts.value_type_btf_obj_fd = -1;
|
||||
exp_err = -524; /* -ENOTSUPP */
|
||||
break;
|
||||
case BPF_MAP_TYPE_BLOOM_FILTER:
|
||||
key_size = 0;
|
||||
max_entries = 1;
|
||||
break;
|
||||
case BPF_MAP_TYPE_ARENA:
|
||||
key_size = 0;
|
||||
value_size = 0;
|
||||
max_entries = 1; /* one page */
|
||||
opts.map_extra = 0; /* can mmap() at any address */
|
||||
opts.map_flags = BPF_F_MMAPABLE;
|
||||
break;
|
||||
case BPF_MAP_TYPE_HASH:
|
||||
case BPF_MAP_TYPE_ARRAY:
|
||||
case BPF_MAP_TYPE_PROG_ARRAY:
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
#define __LIBBPF_VERSION_H
|
||||
|
||||
#define LIBBPF_MAJOR_VERSION 1
|
||||
#define LIBBPF_MINOR_VERSION 4
|
||||
#define LIBBPF_MINOR_VERSION 3
|
||||
|
||||
#endif /* __LIBBPF_VERSION_H */
|
||||
|
||||
33
src/linker.c
33
src/linker.c
@@ -719,28 +719,13 @@ static int linker_sanity_check_elf(struct src_obj *obj)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_dwarf_sec_name(sec->sec_name))
|
||||
continue;
|
||||
if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign))
|
||||
return -EINVAL;
|
||||
if (sec->shdr->sh_addralign != sec->data->d_align)
|
||||
return -EINVAL;
|
||||
|
||||
if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) {
|
||||
pr_warn("ELF section #%zu alignment %llu is non pow-of-2 alignment in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign,
|
||||
obj->filename);
|
||||
if (sec->shdr->sh_size != sec->data->d_size)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (sec->shdr->sh_addralign != sec->data->d_align) {
|
||||
pr_warn("ELF section #%zu has inconsistent alignment addr=%llu != d=%llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign,
|
||||
(long long unsigned)sec->data->d_align, obj->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sec->shdr->sh_size != sec->data->d_size) {
|
||||
pr_warn("ELF section #%zu has inconsistent section size sh=%llu != d=%llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_size,
|
||||
(long long unsigned)sec->data->d_size, obj->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (sec->shdr->sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
@@ -752,12 +737,8 @@ static int linker_sanity_check_elf(struct src_obj *obj)
|
||||
break;
|
||||
case SHT_PROGBITS:
|
||||
if (sec->shdr->sh_flags & SHF_EXECINSTR) {
|
||||
if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) {
|
||||
pr_warn("ELF section #%zu has unexpected size alignment %llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_size,
|
||||
obj->filename);
|
||||
if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHT_NOBITS:
|
||||
@@ -2732,7 +2713,7 @@ static int finalize_btf(struct bpf_linker *linker)
|
||||
|
||||
/* Emit .BTF.ext section */
|
||||
if (linker->btf_ext) {
|
||||
raw_data = btf_ext__raw_data(linker->btf_ext, &raw_sz);
|
||||
raw_data = btf_ext__get_raw_data(linker->btf_ext, &raw_sz);
|
||||
if (!raw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ struct xdp_id_md {
|
||||
|
||||
struct xdp_features_md {
|
||||
int ifindex;
|
||||
__u32 xdp_zc_max_segs;
|
||||
__u64 flags;
|
||||
};
|
||||
|
||||
@@ -422,9 +421,6 @@ static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||
return NL_CONT;
|
||||
|
||||
md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]);
|
||||
if (tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS])
|
||||
md->xdp_zc_max_segs =
|
||||
libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS]);
|
||||
return NL_DONE;
|
||||
}
|
||||
|
||||
@@ -496,8 +492,7 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
if (err)
|
||||
return libbpf_err(err);
|
||||
|
||||
OPTS_SET(opts, feature_flags, md.flags);
|
||||
OPTS_SET(opts, xdp_zc_max_segs, md.xdp_zc_max_segs);
|
||||
opts->feature_flags = md.flags;
|
||||
|
||||
skip_feature_flags:
|
||||
return 0;
|
||||
|
||||
@@ -776,7 +776,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
|
||||
break;
|
||||
case BPF_CORE_FIELD_SIGNED:
|
||||
*val = (btf_is_any_enum(mt) && BTF_INFO_KFLAG(mt->info)) ||
|
||||
(btf_is_int(mt) && (btf_int_encoding(mt) & BTF_INT_SIGNED));
|
||||
(btf_int_encoding(mt) & BTF_INT_SIGNED);
|
||||
if (validate)
|
||||
*validate = true; /* signedness is never ambiguous */
|
||||
break;
|
||||
|
||||
@@ -34,7 +34,7 @@ struct ring {
|
||||
|
||||
struct ring_buffer {
|
||||
struct epoll_event *events;
|
||||
struct ring **rings;
|
||||
struct ring *rings;
|
||||
size_t page_size;
|
||||
int epoll_fd;
|
||||
int ring_cnt;
|
||||
@@ -57,7 +57,7 @@ struct ringbuf_hdr {
|
||||
__u32 pad;
|
||||
};
|
||||
|
||||
static void ringbuf_free_ring(struct ring_buffer *rb, struct ring *r)
|
||||
static void ringbuf_unmap_ring(struct ring_buffer *rb, struct ring *r)
|
||||
{
|
||||
if (r->consumer_pos) {
|
||||
munmap(r->consumer_pos, rb->page_size);
|
||||
@@ -67,8 +67,6 @@ static void ringbuf_free_ring(struct ring_buffer *rb, struct ring *r)
|
||||
munmap(r->producer_pos, rb->page_size + 2 * (r->mask + 1));
|
||||
r->producer_pos = NULL;
|
||||
}
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
/* Add extra RINGBUF maps to this ring buffer manager */
|
||||
@@ -109,10 +107,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
return libbpf_err(-ENOMEM);
|
||||
rb->events = tmp;
|
||||
|
||||
r = calloc(1, sizeof(*r));
|
||||
if (!r)
|
||||
return libbpf_err(-ENOMEM);
|
||||
rb->rings[rb->ring_cnt] = r;
|
||||
r = &rb->rings[rb->ring_cnt];
|
||||
memset(r, 0, sizeof(*r));
|
||||
|
||||
r->map_fd = map_fd;
|
||||
r->sample_cb = sample_cb;
|
||||
@@ -125,7 +121,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
return libbpf_err(err);
|
||||
}
|
||||
r->consumer_pos = tmp;
|
||||
|
||||
@@ -135,16 +131,16 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
*/
|
||||
mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;
|
||||
if (mmap_sz != (__u64)(size_t)mmap_sz) {
|
||||
err = -E2BIG;
|
||||
pr_warn("ringbuf: ring buffer size (%u) is too big\n", info.max_entries);
|
||||
goto err_out;
|
||||
return libbpf_err(-E2BIG);
|
||||
}
|
||||
tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ, MAP_SHARED, map_fd, rb->page_size);
|
||||
if (tmp == MAP_FAILED) {
|
||||
err = -errno;
|
||||
ringbuf_unmap_ring(rb, r);
|
||||
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
return libbpf_err(err);
|
||||
}
|
||||
r->producer_pos = tmp;
|
||||
r->data = tmp + rb->page_size;
|
||||
@@ -156,17 +152,14 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
e->data.fd = rb->ring_cnt;
|
||||
if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, e) < 0) {
|
||||
err = -errno;
|
||||
ringbuf_unmap_ring(rb, r);
|
||||
pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
rb->ring_cnt++;
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
ringbuf_free_ring(rb, r);
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
void ring_buffer__free(struct ring_buffer *rb)
|
||||
@@ -177,7 +170,7 @@ void ring_buffer__free(struct ring_buffer *rb)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rb->ring_cnt; ++i)
|
||||
ringbuf_free_ring(rb, rb->rings[i]);
|
||||
ringbuf_unmap_ring(rb, &rb->rings[i]);
|
||||
if (rb->epoll_fd >= 0)
|
||||
close(rb->epoll_fd);
|
||||
|
||||
@@ -285,7 +278,7 @@ int ring_buffer__consume(struct ring_buffer *rb)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rb->ring_cnt; i++) {
|
||||
struct ring *ring = rb->rings[i];
|
||||
struct ring *ring = &rb->rings[i];
|
||||
|
||||
err = ringbuf_process_ring(ring);
|
||||
if (err < 0)
|
||||
@@ -312,7 +305,7 @@ int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms)
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
__u32 ring_id = rb->events[i].data.fd;
|
||||
struct ring *ring = rb->rings[ring_id];
|
||||
struct ring *ring = &rb->rings[ring_id];
|
||||
|
||||
err = ringbuf_process_ring(ring);
|
||||
if (err < 0)
|
||||
@@ -330,58 +323,6 @@ int ring_buffer__epoll_fd(const struct ring_buffer *rb)
|
||||
return rb->epoll_fd;
|
||||
}
|
||||
|
||||
struct ring *ring_buffer__ring(struct ring_buffer *rb, unsigned int idx)
|
||||
{
|
||||
if (idx >= rb->ring_cnt)
|
||||
return errno = ERANGE, NULL;
|
||||
|
||||
return rb->rings[idx];
|
||||
}
|
||||
|
||||
unsigned long ring__consumer_pos(const struct ring *r)
|
||||
{
|
||||
/* Synchronizes with smp_store_release() in ringbuf_process_ring(). */
|
||||
return smp_load_acquire(r->consumer_pos);
|
||||
}
|
||||
|
||||
unsigned long ring__producer_pos(const struct ring *r)
|
||||
{
|
||||
/* Synchronizes with smp_store_release() in __bpf_ringbuf_reserve() in
|
||||
* the kernel.
|
||||
*/
|
||||
return smp_load_acquire(r->producer_pos);
|
||||
}
|
||||
|
||||
size_t ring__avail_data_size(const struct ring *r)
|
||||
{
|
||||
unsigned long cons_pos, prod_pos;
|
||||
|
||||
cons_pos = ring__consumer_pos(r);
|
||||
prod_pos = ring__producer_pos(r);
|
||||
return prod_pos - cons_pos;
|
||||
}
|
||||
|
||||
size_t ring__size(const struct ring *r)
|
||||
{
|
||||
return r->mask + 1;
|
||||
}
|
||||
|
||||
int ring__map_fd(const struct ring *r)
|
||||
{
|
||||
return r->map_fd;
|
||||
}
|
||||
|
||||
int ring__consume(struct ring *r)
|
||||
{
|
||||
int64_t res;
|
||||
|
||||
res = ringbuf_process_ring(r);
|
||||
if (res < 0)
|
||||
return libbpf_err(res);
|
||||
|
||||
return res > INT_MAX ? INT_MAX : res;
|
||||
}
|
||||
|
||||
static void user_ringbuf_unmap_ring(struct user_ring_buffer *rb)
|
||||
{
|
||||
if (rb->consumer_pos) {
|
||||
|
||||
@@ -2,8 +2,5 @@
|
||||
#ifndef __LIBBPF_STR_ERROR_H
|
||||
#define __LIBBPF_STR_ERROR_H
|
||||
|
||||
#define STRERR_BUFSIZE 128
|
||||
|
||||
char *libbpf_strerror_r(int err, char *dst, int len);
|
||||
|
||||
#endif /* __LIBBPF_STR_ERROR_H */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#define __USDT_BPF_H__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include "bpf_tracing.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
/* Below types and maps are internal implementation details of libbpf's USDT
|
||||
* support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
|
||||
|
||||
121
src/usdt.c
121
src/usdt.c
@@ -250,7 +250,6 @@ struct usdt_manager {
|
||||
|
||||
bool has_bpf_cookie;
|
||||
bool has_sema_refcnt;
|
||||
bool has_uprobe_multi;
|
||||
};
|
||||
|
||||
struct usdt_manager *usdt_manager_new(struct bpf_object *obj)
|
||||
@@ -285,11 +284,6 @@ struct usdt_manager *usdt_manager_new(struct bpf_object *obj)
|
||||
*/
|
||||
man->has_sema_refcnt = faccessat(AT_FDCWD, ref_ctr_sysfs_path, F_OK, AT_EACCESS) == 0;
|
||||
|
||||
/*
|
||||
* Detect kernel support for uprobe multi link to be used for attaching
|
||||
* usdt probes.
|
||||
*/
|
||||
man->has_uprobe_multi = kernel_supports(obj, FEAT_UPROBE_MULTI_LINK);
|
||||
return man;
|
||||
}
|
||||
|
||||
@@ -814,8 +808,6 @@ struct bpf_link_usdt {
|
||||
long abs_ip;
|
||||
struct bpf_link *link;
|
||||
} *uprobes;
|
||||
|
||||
struct bpf_link *multi_link;
|
||||
};
|
||||
|
||||
static int bpf_link_usdt_detach(struct bpf_link *link)
|
||||
@@ -824,9 +816,6 @@ static int bpf_link_usdt_detach(struct bpf_link *link)
|
||||
struct usdt_manager *man = usdt_link->usdt_man;
|
||||
int i;
|
||||
|
||||
bpf_link__destroy(usdt_link->multi_link);
|
||||
|
||||
/* When having multi_link, uprobe_cnt is 0 */
|
||||
for (i = 0; i < usdt_link->uprobe_cnt; i++) {
|
||||
/* detach underlying uprobe link */
|
||||
bpf_link__destroy(usdt_link->uprobes[i].link);
|
||||
@@ -863,11 +852,8 @@ static int bpf_link_usdt_detach(struct bpf_link *link)
|
||||
* system is so exhausted on memory, it's the least of user's
|
||||
* concerns, probably.
|
||||
* 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 || new_cnt == 0) {
|
||||
if (new_free_ids) {
|
||||
memcpy(new_free_ids + man->free_spec_cnt, usdt_link->spec_ids,
|
||||
usdt_link->spec_cnt * sizeof(*usdt_link->spec_ids));
|
||||
man->free_spec_ids = new_free_ids;
|
||||
@@ -957,24 +943,32 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
const char *usdt_provider, const char *usdt_name,
|
||||
__u64 usdt_cookie)
|
||||
{
|
||||
unsigned long *offsets = NULL, *ref_ctr_offsets = NULL;
|
||||
int i, err, spec_map_fd, ip_map_fd;
|
||||
int i, fd, err, spec_map_fd, ip_map_fd;
|
||||
LIBBPF_OPTS(bpf_uprobe_opts, opts);
|
||||
struct hashmap *specs_hash = NULL;
|
||||
struct bpf_link_usdt *link = NULL;
|
||||
struct usdt_target *targets = NULL;
|
||||
__u64 *cookies = NULL;
|
||||
struct elf_fd elf_fd;
|
||||
size_t target_cnt;
|
||||
Elf *elf;
|
||||
|
||||
spec_map_fd = bpf_map__fd(man->specs_map);
|
||||
ip_map_fd = bpf_map__fd(man->ip_to_spec_id_map);
|
||||
|
||||
err = elf_open(path, &elf_fd);
|
||||
if (err)
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("usdt: failed to open ELF binary '%s': %d\n", path, err);
|
||||
return libbpf_err_ptr(err);
|
||||
}
|
||||
|
||||
err = sanity_check_usdt_elf(elf_fd.elf, path);
|
||||
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!elf) {
|
||||
err = -EBADF;
|
||||
pr_warn("usdt: failed to parse ELF binary '%s': %s\n", path, elf_errmsg(-1));
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = sanity_check_usdt_elf(elf, path);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@@ -987,7 +981,7 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
/* discover USDT in given binary, optionally limiting
|
||||
* activations to a given PID, if pid > 0
|
||||
*/
|
||||
err = collect_usdt_targets(man, elf_fd.elf, path, pid, usdt_provider, usdt_name,
|
||||
err = collect_usdt_targets(man, elf, path, pid, usdt_provider, usdt_name,
|
||||
usdt_cookie, &targets, &target_cnt);
|
||||
if (err <= 0) {
|
||||
err = (err == 0) ? -ENOENT : err;
|
||||
@@ -1010,21 +1004,10 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
link->link.detach = &bpf_link_usdt_detach;
|
||||
link->link.dealloc = &bpf_link_usdt_dealloc;
|
||||
|
||||
if (man->has_uprobe_multi) {
|
||||
offsets = calloc(target_cnt, sizeof(*offsets));
|
||||
cookies = calloc(target_cnt, sizeof(*cookies));
|
||||
ref_ctr_offsets = calloc(target_cnt, sizeof(*ref_ctr_offsets));
|
||||
|
||||
if (!offsets || !ref_ctr_offsets || !cookies) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
link->uprobes = calloc(target_cnt, sizeof(*link->uprobes));
|
||||
if (!link->uprobes) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
link->uprobes = calloc(target_cnt, sizeof(*link->uprobes));
|
||||
if (!link->uprobes) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < target_cnt; i++) {
|
||||
@@ -1065,65 +1048,37 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (man->has_uprobe_multi) {
|
||||
offsets[i] = target->rel_ip;
|
||||
ref_ctr_offsets[i] = target->sema_off;
|
||||
cookies[i] = spec_id;
|
||||
} else {
|
||||
opts.ref_ctr_offset = target->sema_off;
|
||||
opts.bpf_cookie = man->has_bpf_cookie ? spec_id : 0;
|
||||
uprobe_link = bpf_program__attach_uprobe_opts(prog, pid, path,
|
||||
target->rel_ip, &opts);
|
||||
err = libbpf_get_error(uprobe_link);
|
||||
if (err) {
|
||||
pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n",
|
||||
i, usdt_provider, usdt_name, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
link->uprobes[i].link = uprobe_link;
|
||||
link->uprobes[i].abs_ip = target->abs_ip;
|
||||
link->uprobe_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (man->has_uprobe_multi) {
|
||||
LIBBPF_OPTS(bpf_uprobe_multi_opts, opts_multi,
|
||||
.ref_ctr_offsets = ref_ctr_offsets,
|
||||
.offsets = offsets,
|
||||
.cookies = cookies,
|
||||
.cnt = target_cnt,
|
||||
);
|
||||
|
||||
link->multi_link = bpf_program__attach_uprobe_multi(prog, pid, path,
|
||||
NULL, &opts_multi);
|
||||
if (!link->multi_link) {
|
||||
err = -errno;
|
||||
pr_warn("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %d\n",
|
||||
usdt_provider, usdt_name, path, err);
|
||||
opts.ref_ctr_offset = target->sema_off;
|
||||
opts.bpf_cookie = man->has_bpf_cookie ? spec_id : 0;
|
||||
uprobe_link = bpf_program__attach_uprobe_opts(prog, pid, path,
|
||||
target->rel_ip, &opts);
|
||||
err = libbpf_get_error(uprobe_link);
|
||||
if (err) {
|
||||
pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n",
|
||||
i, usdt_provider, usdt_name, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
free(offsets);
|
||||
free(ref_ctr_offsets);
|
||||
free(cookies);
|
||||
link->uprobes[i].link = uprobe_link;
|
||||
link->uprobes[i].abs_ip = target->abs_ip;
|
||||
link->uprobe_cnt++;
|
||||
}
|
||||
|
||||
free(targets);
|
||||
hashmap__free(specs_hash);
|
||||
elf_close(&elf_fd);
|
||||
elf_end(elf);
|
||||
close(fd);
|
||||
|
||||
return &link->link;
|
||||
|
||||
err_out:
|
||||
free(offsets);
|
||||
free(ref_ctr_offsets);
|
||||
free(cookies);
|
||||
|
||||
if (link)
|
||||
bpf_link__destroy(&link->link);
|
||||
free(targets);
|
||||
hashmap__free(specs_hash);
|
||||
elf_close(&elf_fd);
|
||||
if (elf)
|
||||
elf_end(elf);
|
||||
close(fd);
|
||||
return libbpf_err_ptr(err);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user