Compare commits
373 Commits
v0.8.1_net
...
netdata_pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9907894225 | ||
|
|
dd7dd01114 | ||
|
|
fbd60dbff5 | ||
|
|
44b0bc9ad7 | ||
|
|
f0e39b4946 | ||
|
|
294c85e9b3 | ||
|
|
2293c20f82 | ||
|
|
e6cc30f445 | ||
|
|
6fd310547d | ||
|
|
0db753a9f8 | ||
|
|
44f59ec077 | ||
|
|
2f01564c50 | ||
|
|
c2fe7adb33 | ||
|
|
88004dd87a | ||
|
|
a22abb9c85 | ||
|
|
2c0c927a38 | ||
|
|
d9d17f6d71 | ||
|
|
3783577161 | ||
|
|
75c14163b9 | ||
|
|
056e9bcc19 | ||
|
|
14ae9422db | ||
|
|
3fd6eebb2d | ||
|
|
4218389b1e | ||
|
|
ae32d7169d | ||
|
|
b362bb6e10 | ||
|
|
f8cd00f613 | ||
|
|
dc4e7076ad | ||
|
|
465a73051d | ||
|
|
e51cdaaca0 | ||
|
|
055cbdcc9f | ||
|
|
c6893dccd9 | ||
|
|
077bf73900 | ||
|
|
68cd7cd386 | ||
|
|
a5464a5b0e | ||
|
|
753e4d07d1 | ||
|
|
5b45c90c49 | ||
|
|
2db620d982 | ||
|
|
c401b96718 | ||
|
|
fd28ca4b5b | ||
|
|
c722f76593 | ||
|
|
b5e9722ec2 | ||
|
|
7fdf16de6d | ||
|
|
faae78aac4 | ||
|
|
950cffc036 | ||
|
|
bdc7c5e217 | ||
|
|
e8107c3959 | ||
|
|
c5be1b0770 | ||
|
|
32d34a9415 | ||
|
|
aab5f194e1 | ||
|
|
c5fe344018 | ||
|
|
232f42135a | ||
|
|
cc7177624f | ||
|
|
cf46d44f0a | ||
|
|
a41e6ef325 | ||
|
|
c2495832ce | ||
|
|
bfb1e97426 | ||
|
|
a468b16788 | ||
|
|
6c673bb00b | ||
|
|
b6c58f7619 | ||
|
|
db26142ffb | ||
|
|
47eb62005a | ||
|
|
9ca6f946cd | ||
|
|
87695e9723 | ||
|
|
3706449b1b | ||
|
|
4c75268933 | ||
|
|
3fe3cccb06 | ||
|
|
0c5b5b5d91 | ||
|
|
d16fc1f0f5 | ||
|
|
37922c6fb2 | ||
|
|
19cd9a1d4b | ||
|
|
a6c64dbfa2 | ||
|
|
0d7ac28818 | ||
|
|
3fdc11b883 | ||
|
|
e198fdc928 | ||
|
|
e114bd2657 | ||
|
|
bb0f8b32a5 | ||
|
|
f9106f6bac | ||
|
|
7ef34fa945 | ||
|
|
7cfc12cb41 | ||
|
|
c16cae9381 | ||
|
|
768164af0e | ||
|
|
30f6bc3c0a | ||
|
|
ea28429902 | ||
|
|
34212c94a6 | ||
|
|
6f1c8eddb2 | ||
|
|
4b492df97e | ||
|
|
24476fe699 | ||
|
|
d74065659a | ||
|
|
418962b686 | ||
|
|
8c8243a409 | ||
|
|
6333ea6a3a | ||
|
|
855bf91055 | ||
|
|
5e0270f66e | ||
|
|
547881e04e | ||
|
|
41b96a8c08 | ||
|
|
700d755151 | ||
|
|
981da2b380 | ||
|
|
23898cf858 | ||
|
|
7285d529cf | ||
|
|
dd460a52bc | ||
|
|
44c1d381ff | ||
|
|
522fe6f721 | ||
|
|
04aafdf9c9 | ||
|
|
416620416f | ||
|
|
6b4a3f3131 | ||
|
|
d73ecc91e1 | ||
|
|
c2e797c8de | ||
|
|
f99818dd1a | ||
|
|
b2e29a1026 | ||
|
|
e398e7eaf4 | ||
|
|
c93ba3907f | ||
|
|
112479afb7 | ||
|
|
004ed7120b | ||
|
|
97740e5103 | ||
|
|
ef191974b3 | ||
|
|
ed66fb297d | ||
|
|
2c58ba33fb | ||
|
|
9a6f8da473 | ||
|
|
a005bb2ff8 | ||
|
|
7f627a6202 | ||
|
|
a095b4f04d | ||
|
|
bd6e1ec311 | ||
|
|
b2d8a8d269 | ||
|
|
df16188dc2 | ||
|
|
672401ae09 | ||
|
|
ed8b4c90ea | ||
|
|
2094e1b37e | ||
|
|
c978366c38 | ||
|
|
9db84de5f0 | ||
|
|
ffbc84cf6f | ||
|
|
7b86294a90 | ||
|
|
31e29d9346 | ||
|
|
1b48e879a4 | ||
|
|
4759a83309 | ||
|
|
c94a3fd806 | ||
|
|
7d68fca99c | ||
|
|
ed09f7e65b | ||
|
|
49e950dcfa | ||
|
|
ce8d078ac7 | ||
|
|
42d77b062c | ||
|
|
d572b6359e | ||
|
|
f758104b07 | ||
|
|
b92963bbe2 | ||
|
|
34fadd0fbe | ||
|
|
09f1324bd7 | ||
|
|
8cd371816b | ||
|
|
7d075a739e | ||
|
|
3423d5e7cd | ||
|
|
e3a40329bb | ||
|
|
a16e904d6c | ||
|
|
6597330c45 | ||
|
|
2e287cd201 | ||
|
|
49bd40e869 | ||
|
|
f7dba2c313 | ||
|
|
41ac436073 | ||
|
|
75987cc295 | ||
|
|
b9f1a06c70 | ||
|
|
30554b08fe | ||
|
|
b0ff8e90f7 | ||
|
|
0b80970cb6 | ||
|
|
58b164237a | ||
|
|
e6e0e3fd85 | ||
|
|
db11704944 | ||
|
|
8d719b0c08 | ||
|
|
6b90604fa7 | ||
|
|
74244c5bd7 | ||
|
|
da08611c65 | ||
|
|
1e479aec4f | ||
|
|
8846dc7a20 | ||
|
|
eb9b5c567d | ||
|
|
be8f15bb93 | ||
|
|
2bf5ed3a48 | ||
|
|
0fbf777e0b | ||
|
|
4d21c979ce | ||
|
|
11ad834557 | ||
|
|
f056d1bd54 | ||
|
|
b822a139e3 | ||
|
|
a5b4a53781 | ||
|
|
e84419ff5a | ||
|
|
ca515c0dda | ||
|
|
95959419a7 | ||
|
|
3c659715ec | ||
|
|
f46b17ef0e | ||
|
|
1596a09b5d | ||
|
|
5322b8e76c | ||
|
|
15bbaabed8 | ||
|
|
eb77c7210b | ||
|
|
2557efc8e1 | ||
|
|
9781b9eced | ||
|
|
4c3b53d09c | ||
|
|
7b18ff1212 | ||
|
|
c975797ebe | ||
|
|
9167308b4a | ||
|
|
7049d3a2ea | ||
|
|
ea931ec6c5 | ||
|
|
3a73d6f865 | ||
|
|
7b0891ac6b | ||
|
|
c80f12f7f6 | ||
|
|
3b6093fd43 | ||
|
|
8d358ab948 | ||
|
|
971ad8f8d0 | ||
|
|
2ed27f9e63 | ||
|
|
4bdbb7ea28 | ||
|
|
4978cf9cd8 | ||
|
|
00fc9f407c | ||
|
|
e1b34c589d | ||
|
|
7583310911 | ||
|
|
4a65c5d888 | ||
|
|
3a387f5a8f | ||
|
|
a2eba90326 | ||
|
|
7106ebe768 | ||
|
|
3c6d127e50 | ||
|
|
6ebbbacb5c | ||
|
|
1bb7a8349a | ||
|
|
3cd45b660c | ||
|
|
0e195e4597 | ||
|
|
08830e9d2f | ||
|
|
1022f26d04 | ||
|
|
b4ca1f6407 | ||
|
|
fd71ca941b | ||
|
|
a14b39bd31 | ||
|
|
ade228b8f0 | ||
|
|
41ab246bdf | ||
|
|
d918025bc8 | ||
|
|
918d7712c0 | ||
|
|
4a84a7619f | ||
|
|
837664758d | ||
|
|
11bf829873 | ||
|
|
c97b16d96c | ||
|
|
1c17672353 | ||
|
|
68e6f83f22 | ||
|
|
383ffb79a6 | ||
|
|
50315fd763 | ||
|
|
534a2c6f53 | ||
|
|
3a3ef0c1d0 | ||
|
|
3ee4823fcb | ||
|
|
7412775110 | ||
|
|
881a10980b | ||
|
|
54caf920db | ||
|
|
0d6c47523c | ||
|
|
998282f179 | ||
|
|
d6d1ec5b25 | ||
|
|
a719cae6aa | ||
|
|
07024c87de | ||
|
|
19ef40cee6 | ||
|
|
3d3ff49213 | ||
|
|
3745a20b28 | ||
|
|
b9e909dd41 | ||
|
|
73c0c44b67 | ||
|
|
abde7fb314 | ||
|
|
63389d32f6 | ||
|
|
59080bd06c | ||
|
|
8b0b41f812 | ||
|
|
6bd5b40bcd | ||
|
|
6cd8907a4a | ||
|
|
fa2875be8a | ||
|
|
27a93eae7c | ||
|
|
dac1c4b6a8 | ||
|
|
1714037104 | ||
|
|
d598cb20c7 | ||
|
|
ce321d6fd4 | ||
|
|
0f5b3a10ae | ||
|
|
5859c59e50 | ||
|
|
85f8b7c4dc | ||
|
|
9da0dcb621 | ||
|
|
82c4054376 | ||
|
|
b3a117773d | ||
|
|
fc2577c54c | ||
|
|
0420f75dbc | ||
|
|
aa25f218b4 | ||
|
|
9e9bf46c92 | ||
|
|
28903eb40e | ||
|
|
8138aa78bd | ||
|
|
8ac9773f52 | ||
|
|
b63791cbde | ||
|
|
0ff6d28aec | ||
|
|
861364fa45 | ||
|
|
21ec5ca723 | ||
|
|
255690da57 | ||
|
|
b1753eaf3b | ||
|
|
eeb2bc4061 | ||
|
|
a11587cc01 | ||
|
|
7fb6138fae | ||
|
|
c918b3e724 | ||
|
|
981001bf46 | ||
|
|
ee7d295f83 | ||
|
|
94d69cc07f | ||
|
|
12a41a80c5 | ||
|
|
10a32130e7 | ||
|
|
fad270918d | ||
|
|
c091b07808 | ||
|
|
efd33720cd | ||
|
|
9aedff8d03 | ||
|
|
51e63f7229 | ||
|
|
c53af98d1a | ||
|
|
2c44349e09 | ||
|
|
58361243ec | ||
|
|
c32e1cf948 | ||
|
|
c4f44c7c11 | ||
|
|
a7a525d47a | ||
|
|
cfbd763ef8 | ||
|
|
862b60f205 | ||
|
|
a0325403af | ||
|
|
7436656dbf | ||
|
|
7984737fbf | ||
|
|
a0d1e22c77 | ||
|
|
e58c615210 | ||
|
|
aec0b1cd7d | ||
|
|
a202bd7433 | ||
|
|
ba81a5b778 | ||
|
|
f7cee4152f | ||
|
|
06c4624c8c | ||
|
|
c8f4b9c878 | ||
|
|
079bc8536d | ||
|
|
8be13ee80b | ||
|
|
3db7585378 | ||
|
|
69938da6d7 | ||
|
|
bfdf7653e0 | ||
|
|
d700dcf162 | ||
|
|
c03b9f6d0b | ||
|
|
66b788c1a4 | ||
|
|
e3c2b8a48d | ||
|
|
13a26d78f3 | ||
|
|
6b92311c3a | ||
|
|
6fdbfb00f1 | ||
|
|
45dca19bd2 | ||
|
|
2fe1958ec8 | ||
|
|
cbd9b7e5d8 | ||
|
|
0cc6bfab39 | ||
|
|
41c612167e | ||
|
|
69d537ba0b | ||
|
|
bd1e5cff31 | ||
|
|
3d484ca473 | ||
|
|
c25544735b | ||
|
|
179c7940eb | ||
|
|
f6692dc4e8 | ||
|
|
693de729d0 | ||
|
|
0667206913 | ||
|
|
a2ebd9ceff | ||
|
|
0e43565ad8 | ||
|
|
5b795f7b30 | ||
|
|
3fa2c28d2c | ||
|
|
0fa013e705 | ||
|
|
d8e2c9d965 | ||
|
|
b2d7228d7c | ||
|
|
427f2a0c83 | ||
|
|
8663289b51 | ||
|
|
77e514d626 | ||
|
|
b44b214118 | ||
|
|
610707057a | ||
|
|
7e567b8761 | ||
|
|
1fe0248c61 | ||
|
|
0862e4e54d | ||
|
|
fd6c9d906a | ||
|
|
d56d93baff | ||
|
|
1648fa16b5 | ||
|
|
9b6f4eb157 | ||
|
|
b3fe4be0b3 | ||
|
|
6d5026e434 | ||
|
|
ca60209447 | ||
|
|
b31ca3fa0e | ||
|
|
295a4aae35 | ||
|
|
8498996f9f | ||
|
|
aa13a6ff58 | ||
|
|
bace4782cd | ||
|
|
ab2221de84 | ||
|
|
d8a50bfe35 | ||
|
|
95971ddd48 | ||
|
|
7410ddc0f4 | ||
|
|
1b80b97a30 | ||
|
|
434b56c497 | ||
|
|
d060a88aa5 | ||
|
|
9340d9b650 |
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assets/ export-ignore
|
||||||
5
.github/actions/build-selftests/action.yml
vendored
@@ -18,9 +18,10 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- shell: bash
|
- shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "::group::Setup Env"
|
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||||
|
foldable start "Setup Env"
|
||||||
sudo apt-get install -y qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev python3-docutils
|
sudo apt-get install -y qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev python3-docutils
|
||||||
echo "::endgroup::"
|
foldable end
|
||||||
- shell: bash
|
- shell: bash
|
||||||
run: |
|
run: |
|
||||||
export KERNEL=${{ inputs.kernel }}
|
export KERNEL=${{ inputs.kernel }}
|
||||||
|
|||||||
@@ -6,11 +6,28 @@ THISDIR="$(cd $(dirname $0) && pwd)"
|
|||||||
|
|
||||||
source ${THISDIR}/helpers.sh
|
source ${THISDIR}/helpers.sh
|
||||||
|
|
||||||
travis_fold start prepare_selftests "Building selftests"
|
foldable start prepare_selftests "Building selftests"
|
||||||
|
|
||||||
LLVM_VER=15
|
|
||||||
LIBBPF_PATH="${REPO_ROOT}"
|
LIBBPF_PATH="${REPO_ROOT}"
|
||||||
|
|
||||||
|
llvm_default_version() {
|
||||||
|
echo "16"
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_latest_version() {
|
||||||
|
echo "17"
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVM_VERSION=$(llvm_default_version)
|
||||||
|
if [[ "${LLVM_VERSION}" == $(llvm_latest_version) ]]; then
|
||||||
|
REPO_DISTRO_SUFFIX=""
|
||||||
|
else
|
||||||
|
REPO_DISTRO_SUFFIX="-${LLVM_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "deb https://apt.llvm.org/focal/ llvm-toolchain-focal${REPO_DISTRO_SUFFIX} main" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
|
||||||
PREPARE_SELFTESTS_SCRIPT=${THISDIR}/prepare_selftests-${KERNEL}.sh
|
PREPARE_SELFTESTS_SCRIPT=${THISDIR}/prepare_selftests-${KERNEL}.sh
|
||||||
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
|
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
|
||||||
(cd "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" && ${PREPARE_SELFTESTS_SCRIPT})
|
(cd "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" && ${PREPARE_SELFTESTS_SCRIPT})
|
||||||
@@ -24,9 +41,9 @@ fi
|
|||||||
|
|
||||||
cd ${REPO_ROOT}/${REPO_PATH}
|
cd ${REPO_ROOT}/${REPO_PATH}
|
||||||
make \
|
make \
|
||||||
CLANG=clang-${LLVM_VER} \
|
CLANG=clang-${LLVM_VERSION} \
|
||||||
LLC=llc-${LLVM_VER} \
|
LLC=llc-${LLVM_VERSION} \
|
||||||
LLVM_STRIP=llvm-strip-${LLVM_VER} \
|
LLVM_STRIP=llvm-strip-${LLVM_VERSION} \
|
||||||
VMLINUX_BTF="${VMLINUX_BTF}" \
|
VMLINUX_BTF="${VMLINUX_BTF}" \
|
||||||
VMLINUX_H=${VMLINUX_H} \
|
VMLINUX_H=${VMLINUX_H} \
|
||||||
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||||
@@ -39,4 +56,4 @@ cd ${LIBBPF_PATH}
|
|||||||
rm selftests/bpf/.gitignore
|
rm selftests/bpf/.gitignore
|
||||||
git add selftests
|
git add selftests
|
||||||
|
|
||||||
travis_fold end prepare_selftests
|
foldable end prepare_selftests
|
||||||
|
|||||||
22
.github/actions/build-selftests/helpers.sh
vendored
@@ -1,26 +1,20 @@
|
|||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
# $1 - start or end
|
# $1 - start or end
|
||||||
# $2 - fold identifier, no spaces
|
# $2 - fold identifier, no spaces
|
||||||
# $3 - fold section description
|
# $3 - fold section description
|
||||||
travis_fold() {
|
foldable() {
|
||||||
local YELLOW='\033[1;33m'
|
local YELLOW='\033[1;33m'
|
||||||
local NOCOLOR='\033[0m'
|
local NOCOLOR='\033[0m'
|
||||||
if [ -z ${GITHUB_WORKFLOW+x} ]; then
|
if [ $1 = "start" ]; then
|
||||||
echo travis_fold:$1:$2
|
line="::group::$2"
|
||||||
if [ ! -z "${3:-}" ]; then
|
if [ ! -z "${3:-}" ]; then
|
||||||
echo -e "${YELLOW}$3${NOCOLOR}"
|
line="$line - ${YELLOW}$3${NOCOLOR}"
|
||||||
fi
|
fi
|
||||||
echo
|
|
||||||
else
|
else
|
||||||
if [ $1 = "start" ]; then
|
line="::endgroup::"
|
||||||
line="::group::$2"
|
|
||||||
if [ ! -z "${3:-}" ]; then
|
|
||||||
line="$line - ${YELLOW}$3${NOCOLOR}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
line="::endgroup::"
|
|
||||||
fi
|
|
||||||
echo -e "$line"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "$line"
|
||||||
}
|
}
|
||||||
|
|
||||||
__print() {
|
__print() {
|
||||||
|
|||||||
230994
.github/actions/build-selftests/vmlinux.h
vendored
4
.github/actions/setup/action.yml
vendored
@@ -6,7 +6,7 @@ runs:
|
|||||||
- id: variables
|
- id: variables
|
||||||
run: |
|
run: |
|
||||||
export REPO_ROOT=$GITHUB_WORKSPACE
|
export REPO_ROOT=$GITHUB_WORKSPACE
|
||||||
export CI_ROOT=$REPO_ROOT/travis-ci
|
export CI_ROOT=$REPO_ROOT/ci
|
||||||
# this is somewhat ugly, but that is the easiest way to share this code with
|
# this is somewhat ugly, but that is the easiest way to share this code with
|
||||||
# arch specific docker
|
# arch specific docker
|
||||||
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
||||||
@@ -16,7 +16,7 @@ runs:
|
|||||||
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
||||||
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
||||||
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
||||||
echo export CI_ROOT=$REPO_ROOT/travis-ci >> /tmp/ci_setup
|
echo export CI_ROOT=$REPO_ROOT/ci >> /tmp/ci_setup
|
||||||
echo export VMTEST_ROOT=$CI_ROOT/vmtest >> /tmp/ci_setup
|
echo export VMTEST_ROOT=$CI_ROOT/vmtest >> /tmp/ci_setup
|
||||||
echo 'echo ::endgroup::' >> /tmp/ci_setup
|
echo 'echo ::endgroup::' >> /tmp/ci_setup
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
42
.github/actions/vmtest/action.yml
vendored
@@ -16,9 +16,9 @@ inputs:
|
|||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
# setup envinronment
|
# setup environment
|
||||||
- name: Setup environment
|
- name: Setup environment
|
||||||
uses: libbpf/ci/setup-build-env@master
|
uses: libbpf/ci/setup-build-env@main
|
||||||
with:
|
with:
|
||||||
pahole: ${{ inputs.pahole }}
|
pahole: ${{ inputs.pahole }}
|
||||||
# 1. download CHECKPOINT kernel source
|
# 1. download CHECKPOINT kernel source
|
||||||
@@ -28,40 +28,43 @@ runs:
|
|||||||
cat CHECKPOINT-COMMIT
|
cat CHECKPOINT-COMMIT
|
||||||
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
||||||
- name: Get kernel source at checkpoint
|
- name: Get kernel source at checkpoint
|
||||||
uses: libbpf/ci/get-linux-source@master
|
uses: libbpf/ci/get-linux-source@main
|
||||||
with:
|
with:
|
||||||
repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||||
rev: ${{ env.CHECKPOINT }}
|
rev: ${{ env.CHECKPOINT }}
|
||||||
dest: '${{ github.workspace }}/.kernel'
|
dest: '${{ github.workspace }}/.kernel'
|
||||||
- name: Patch kernel source
|
- name: Patch kernel source
|
||||||
uses: libbpf/ci/patch-kernel@master
|
uses: libbpf/ci/patch-kernel@main
|
||||||
with:
|
with:
|
||||||
patches-root: '${{ github.workspace }}/travis-ci/diffs'
|
patches-root: '${{ github.workspace }}/ci/diffs'
|
||||||
repo-root: '.kernel'
|
repo-root: '.kernel'
|
||||||
- name: Prepare to build BPF selftests
|
- name: Prepare to build BPF selftests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "::group::Prepare buidling selftest"
|
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||||
|
foldable start "Prepare building selftest"
|
||||||
cd .kernel
|
cd .kernel
|
||||||
cp ${{ github.workspace }}/travis-ci/vmtest/configs/config-latest.${{ inputs.arch }} .config
|
cat tools/testing/selftests/bpf/config \
|
||||||
|
tools/testing/selftests/bpf/config.${{ inputs.arch }} > .config
|
||||||
make olddefconfig && make prepare
|
make olddefconfig && make prepare
|
||||||
cd -
|
cd -
|
||||||
echo "::endgroup::"
|
foldable end
|
||||||
# 2. if kernel == LATEST, build kernel image from tree
|
# 2. if kernel == LATEST, build kernel image from tree
|
||||||
- name: Build kernel image
|
- name: Build kernel image
|
||||||
if: ${{ inputs.kernel == 'LATEST' }}
|
if: ${{ inputs.kernel == 'LATEST' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "::group::Build Kernel Image"
|
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||||
|
foldable start "Build Kernel Image"
|
||||||
cd .kernel
|
cd .kernel
|
||||||
make -j $((4*$(nproc))) all > /dev/null
|
make -j $((4*$(nproc))) all > /dev/null
|
||||||
cp vmlinux ${{ github.workspace }}
|
cp vmlinux ${{ github.workspace }}
|
||||||
cd -
|
cd -
|
||||||
echo "::endgroup::"
|
foldable end
|
||||||
# else, just download prebuilt kernel image
|
# else, just download prebuilt kernel image
|
||||||
- name: Download prebuilt kernel
|
- name: Download prebuilt kernel
|
||||||
if: ${{ inputs.kernel != 'LATEST' }}
|
if: ${{ inputs.kernel != 'LATEST' }}
|
||||||
uses: libbpf/ci/download-vmlinux@master
|
uses: libbpf/ci/download-vmlinux@main
|
||||||
with:
|
with:
|
||||||
kernel: ${{ inputs.kernel }}
|
kernel: ${{ inputs.kernel }}
|
||||||
arch: ${{ inputs.arch }}
|
arch: ${{ inputs.arch }}
|
||||||
@@ -73,15 +76,24 @@ runs:
|
|||||||
kernel: ${{ inputs.kernel }}
|
kernel: ${{ inputs.kernel }}
|
||||||
# 4. prepare rootfs
|
# 4. prepare rootfs
|
||||||
- name: prepare rootfs
|
- name: prepare rootfs
|
||||||
uses: libbpf/ci/prepare-rootfs@master
|
uses: libbpf/ci/prepare-rootfs@main
|
||||||
|
env:
|
||||||
|
KBUILD_OUTPUT: '.kernel'
|
||||||
with:
|
with:
|
||||||
kernel: ${{ inputs.kernel }}
|
|
||||||
project-name: 'libbpf'
|
project-name: 'libbpf'
|
||||||
arch: ${{ inputs.arch }}
|
arch: ${{ inputs.arch }}
|
||||||
|
kernel: ${{ inputs.kernel }}
|
||||||
|
kernel-root: '.kernel'
|
||||||
|
kbuild-output: ${{ env.KBUILD_OUTPUT }}
|
||||||
|
image-output: '/tmp/root.img'
|
||||||
# 5. run selftest in QEMU
|
# 5. run selftest in QEMU
|
||||||
- name: Run selftests
|
- name: Run selftests
|
||||||
uses: libbpf/ci/run-qemu@master
|
env:
|
||||||
|
KERNEL: ${{ inputs.kernel }}
|
||||||
|
REPO_ROOT: ${{ github.workspace }}
|
||||||
|
uses: libbpf/ci/run-qemu@main
|
||||||
with:
|
with:
|
||||||
|
arch: ${{ inputs.arch }}
|
||||||
img: '/tmp/root.img'
|
img: '/tmp/root.img'
|
||||||
vmlinuz: 'vmlinuz'
|
vmlinuz: 'vmlinuz'
|
||||||
arch: ${{ inputs.arch }}
|
kernel-root: '.kernel'
|
||||||
|
|||||||
22
.github/workflows/build.yml
vendored
@@ -23,16 +23,26 @@ jobs:
|
|||||||
target: RUN
|
target: RUN
|
||||||
- name: ASan+UBSan
|
- name: ASan+UBSan
|
||||||
target: RUN_ASAN
|
target: RUN_ASAN
|
||||||
- name: clang
|
|
||||||
target: RUN_CLANG
|
|
||||||
- name: clang ASan+UBSan
|
- name: clang ASan+UBSan
|
||||||
target: RUN_CLANG_ASAN
|
target: RUN_CLANG_ASAN
|
||||||
- name: gcc-10
|
|
||||||
target: RUN_GCC10
|
|
||||||
- name: gcc-10 ASan+UBSan
|
- name: gcc-10 ASan+UBSan
|
||||||
target: RUN_GCC10_ASAN
|
target: RUN_GCC10_ASAN
|
||||||
|
- name: clang
|
||||||
|
target: RUN_CLANG
|
||||||
|
- name: clang-14
|
||||||
|
target: RUN_CLANG14
|
||||||
|
- name: clang-15
|
||||||
|
target: RUN_CLANG15
|
||||||
|
- name: clang-16
|
||||||
|
target: RUN_CLANG16
|
||||||
|
- name: gcc-10
|
||||||
|
target: RUN_GCC10
|
||||||
|
- name: gcc-11
|
||||||
|
target: RUN_GCC11
|
||||||
|
- name: gcc-12
|
||||||
|
target: RUN_GCC12
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
name: Checkout
|
name: Checkout
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
name: Setup
|
name: Setup
|
||||||
@@ -53,7 +63,7 @@ jobs:
|
|||||||
- arch: s390x
|
- arch: s390x
|
||||||
- arch: x86
|
- arch: x86
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
name: Checkout
|
name: Checkout
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
name: Pre-Setup
|
name: Pre-Setup
|
||||||
|
|||||||
52
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
# vi: ts=2 sw=2 et:
|
||||||
|
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: ['cpp', 'python']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
queries: +security-extended,security-and-quality
|
||||||
|
|
||||||
|
- name: Setup
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
source /tmp/ci_setup
|
||||||
|
make -C ./src
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
7
.github/workflows/coverity.yml
vendored
@@ -11,16 +11,17 @@ jobs:
|
|||||||
if: github.repository == 'libbpf/libbpf'
|
if: github.repository == 'libbpf/libbpf'
|
||||||
name: Coverity
|
name: Coverity
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
- name: Run coverity
|
- name: Run coverity
|
||||||
run: |
|
run: |
|
||||||
echo ::group::Setup CI env
|
source "${GITHUB_WORKSPACE}"/ci/vmtest/helpers.sh
|
||||||
|
foldable start "Setup CI env"
|
||||||
source /tmp/ci_setup
|
source /tmp/ci_setup
|
||||||
export COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
export COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
||||||
export COVERITY_SCAN_BRANCH_PATTERN=${GITHUB_REF##refs/*/}
|
export COVERITY_SCAN_BRANCH_PATTERN=${GITHUB_REF##refs/*/}
|
||||||
export TRAVIS_BRANCH=${COVERITY_SCAN_BRANCH_PATTERN}
|
export TRAVIS_BRANCH=${COVERITY_SCAN_BRANCH_PATTERN}
|
||||||
echo ::endgroup::
|
foldable end
|
||||||
scripts/coverity.sh
|
scripts/coverity.sh
|
||||||
env:
|
env:
|
||||||
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
|||||||
19
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: "lint"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
shellcheck:
|
||||||
|
name: ShellCheck
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Run ShellCheck
|
||||||
|
uses: ludeeus/action-shellcheck@master
|
||||||
|
env:
|
||||||
|
SHELLCHECK_OPTS: --severity=error
|
||||||
2
.github/workflows/ondemand.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: vmtest with customized pahole/Kernel
|
name: vmtest with customized pahole/Kernel
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
- uses: ./.github/actions/vmtest
|
- uses: ./.github/actions/vmtest
|
||||||
with:
|
with:
|
||||||
|
|||||||
4
.github/workflows/pahole.yml
vendored
@@ -7,12 +7,12 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
vmtest:
|
vmtest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
name: Kernel LATEST + staging pahole
|
name: Kernel LATEST + staging pahole
|
||||||
env:
|
env:
|
||||||
STAGING: tmp.master
|
STAGING: tmp.master
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
- uses: ./.github/actions/vmtest
|
- uses: ./.github/actions/vmtest
|
||||||
with:
|
with:
|
||||||
|
|||||||
10
.github/workflows/test.yml
vendored
@@ -19,19 +19,19 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- kernel: 'LATEST'
|
- kernel: 'LATEST'
|
||||||
runs_on: ubuntu-latest
|
runs_on: ubuntu-20.04
|
||||||
arch: 'x86_64'
|
arch: 'x86_64'
|
||||||
- kernel: '5.5.0'
|
- kernel: '5.5.0'
|
||||||
runs_on: ubuntu-latest
|
runs_on: ubuntu-20.04
|
||||||
arch: 'x86_64'
|
arch: 'x86_64'
|
||||||
- kernel: '4.9.0'
|
- kernel: '4.9.0'
|
||||||
runs_on: ubuntu-latest
|
runs_on: ubuntu-20.04
|
||||||
arch: 'x86_64'
|
arch: 'x86_64'
|
||||||
- kernel: 'LATEST'
|
- kernel: 'LATEST'
|
||||||
runs_on: z15
|
runs_on: s390x
|
||||||
arch: 's390x'
|
arch: 's390x'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
name: Checkout
|
name: Checkout
|
||||||
- uses: ./.github/actions/setup
|
- uses: ./.github/actions/setup
|
||||||
name: Setup
|
name: Setup
|
||||||
|
|||||||
14
.lgtm.yml
@@ -1,14 +0,0 @@
|
|||||||
# vi: set ts=2 sw=2:
|
|
||||||
extraction:
|
|
||||||
cpp:
|
|
||||||
prepare:
|
|
||||||
packages:
|
|
||||||
- libelf-dev
|
|
||||||
- pkg-config
|
|
||||||
after_prepare:
|
|
||||||
# As the buildsystem detection by LGTM is performed _only_ during the
|
|
||||||
# 'configure' phase, we need to trick LGTM we use a supported build
|
|
||||||
# system (configure, meson, cmake, etc.). This way LGTM correctly detects
|
|
||||||
# that our sources are in the src/ subfolder.
|
|
||||||
- touch src/configure
|
|
||||||
- chmod +x src/configure
|
|
||||||
@@ -1 +1 @@
|
|||||||
d28b25a62a47a8c8aa19bd543863aab6717e68c9
|
71b547f561247897a0a14f3082730156c0533fed
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
b0d93b44641a83c28014ca38001e85bf6dc8501e
|
2ddade322925641ee2a75f13665c51f2e74d7791
|
||||||
|
|||||||
60
README.md
@@ -1,17 +1,33 @@
|
|||||||
This is a mirror of [bpf-next Linux source
|
<picture>
|
||||||
tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next)'s
|
<source media="(prefers-color-scheme: dark)" srcset="assets/libbpf-logo-sideways-darkbg.png" width="40%">
|
||||||
`tools/lib/bpf` directory plus its supporting header files.
|
<img src="assets/libbpf-logo-sideways.png" width="40%">
|
||||||
|
</picture>
|
||||||
|
|
||||||
All the gory details of syncing can be found in `scripts/sync-kernel.sh`
|
libbpf
|
||||||
script.
|
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
||||||
|
[](https://scan.coverity.com/projects/libbpf)
|
||||||
|
[](https://github.com/libbpf/libbpf/actions?query=workflow%3ACodeQL+branch%3Amaster)
|
||||||
|
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libbpf)
|
||||||
|
[](https://libbpf.readthedocs.io/en/latest/)
|
||||||
|
======
|
||||||
|
|
||||||
Some header files in this repo (`include/linux/*.h`) are reduced versions of
|
**This is the official home of the libbpf library.**
|
||||||
their counterpart files at
|
|
||||||
[bpf-next](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/)'s
|
|
||||||
`tools/include/linux/*.h` to make compilation successful.
|
|
||||||
|
|
||||||
BPF/libbpf usage and questions
|
*Please use this Github repository for building and packaging libbpf
|
||||||
==============================
|
and when using it in your projects through Git submodule.*
|
||||||
|
|
||||||
|
Libbpf *authoritative source code* is developed as part of [bpf-next Linux source
|
||||||
|
tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next) under
|
||||||
|
`tools/lib/bpf` subdirectory and is periodically synced to Github. As such, all the
|
||||||
|
libbpf changes should be sent to [BPF mailing list](http://vger.kernel.org/vger-lists.html#bpf),
|
||||||
|
please don't open PRs here unless you are changing Github-specific parts of libbpf
|
||||||
|
(e.g., Github-specific Makefile).
|
||||||
|
|
||||||
|
Libbpf and general BPF usage questions
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Libbpf documentation can be found [here](https://libbpf.readthedocs.io/en/latest/api.html).
|
||||||
|
It's an ongoing effort and has ways to go, but please take a look and consider contributing as well.
|
||||||
|
|
||||||
Please check out [libbpf-bootstrap](https://github.com/libbpf/libbpf-bootstrap)
|
Please check out [libbpf-bootstrap](https://github.com/libbpf/libbpf-bootstrap)
|
||||||
and [the companion blog post](https://nakryiko.com/posts/libbpf-bootstrap/) for
|
and [the companion blog post](https://nakryiko.com/posts/libbpf-bootstrap/) for
|
||||||
@@ -36,12 +52,8 @@ to help you with whatever issue you have. This repository's PRs and issues
|
|||||||
should be opened only for dealing with issues pertaining to specific way this
|
should be opened only for dealing with issues pertaining to specific way this
|
||||||
libbpf mirror repo is set up and organized.
|
libbpf mirror repo is set up and organized.
|
||||||
|
|
||||||
Build
|
Building libbpf
|
||||||
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
===============
|
||||||
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
|
||||||
[](https://scan.coverity.com/projects/libbpf)
|
|
||||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libbpf)
|
|
||||||
=====
|
|
||||||
libelf is an internal dependency of libbpf and thus it is required to link
|
libelf is an internal dependency of libbpf and thus it is required to link
|
||||||
against and must be installed on the system for applications to work.
|
against and must be installed on the system for applications to work.
|
||||||
pkg-config is used by default to find libelf, and the program called can be
|
pkg-config is used by default to find libelf, and the program called can be
|
||||||
@@ -133,7 +145,7 @@ Distributions packaging libbpf from this mirror:
|
|||||||
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
||||||
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||||
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
||||||
- [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
|
- [Arch](https://archlinux.org/packages/core/x86_64/libbpf/)
|
||||||
- [Ubuntu](https://packages.ubuntu.com/source/impish/libbpf)
|
- [Ubuntu](https://packages.ubuntu.com/source/impish/libbpf)
|
||||||
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
||||||
|
|
||||||
@@ -156,6 +168,18 @@ Package dependencies of libbpf, package names may vary across distros:
|
|||||||
|
|
||||||
[](https://repology.org/project/libbpf/versions)
|
[](https://repology.org/project/libbpf/versions)
|
||||||
|
|
||||||
|
|
||||||
|
bpf-next to Github sync
|
||||||
|
=======================
|
||||||
|
|
||||||
|
All the gory details of syncing can be found in `scripts/sync-kernel.sh`
|
||||||
|
script. See [SYNC.md](SYNC.md) for instruction.
|
||||||
|
|
||||||
|
Some header files in this repo (`include/linux/*.h`) are reduced versions of
|
||||||
|
their counterpart files at
|
||||||
|
[bpf-next](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/)'s
|
||||||
|
`tools/include/linux/*.h` to make compilation successful.
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|||||||
281
SYNC.md
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="assets/libbpf-logo-sideways-darkbg.png" width="40%">
|
||||||
|
<img src="assets/libbpf-logo-sideways.png" width="40%">
|
||||||
|
</picture>
|
||||||
|
|
||||||
|
Libbpf sync
|
||||||
|
===========
|
||||||
|
|
||||||
|
Libbpf *authoritative source code* is developed as part of [bpf-next Linux source
|
||||||
|
tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next) under
|
||||||
|
`tools/lib/bpf` subdirectory and is periodically synced to Github.
|
||||||
|
|
||||||
|
Most of the mundane mechanical things like bpf and bpf-next tree merge, Git
|
||||||
|
history transformation, cherry-picking relevant commits, re-generating
|
||||||
|
auto-generated headers, etc. are taken care by
|
||||||
|
[sync-kernel.sh script](https://github.com/libbpf/libbpf/blob/master/scripts/sync-kernel.sh).
|
||||||
|
But occasionally human needs to do few extra things to make everything work
|
||||||
|
nicely.
|
||||||
|
|
||||||
|
This document goes over the process of syncing libbpf sources from Linux repo
|
||||||
|
to this Github repository. Feel free to contribute fixes and additions if you
|
||||||
|
run into new problems not outlined here.
|
||||||
|
|
||||||
|
Setup expectations
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Sync script has particular expectation of upstream Linux repo setup. It
|
||||||
|
expects that current HEAD of that repo points to bpf-next's master branch and
|
||||||
|
that there is a separate local branch pointing to bpf tree's master branch.
|
||||||
|
This is important, as the script will automatically merge their histories for
|
||||||
|
the purpose of libbpf sync.
|
||||||
|
|
||||||
|
Below, we assume that Linux repo is located at `~/linux`, it's current head is
|
||||||
|
at latest `bpf-next/master`, and libbpf's Github repo is located at
|
||||||
|
`~/libbpf`, checked out to latest commit on `master` branch. It doesn't matter
|
||||||
|
from where to run `sync-kernel.sh` script, but we'll be running it from inside
|
||||||
|
`~/libbpf`.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd ~/linux && git remote -v | grep -E '^(bpf|bpf-next)'
|
||||||
|
bpf https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git (fetch)
|
||||||
|
bpf ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
|
||||||
|
(push)
|
||||||
|
bpf-next
|
||||||
|
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git (fetch)
|
||||||
|
bpf-next
|
||||||
|
ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git (push)
|
||||||
|
$ git branch -vv | grep -E '^? (master|bpf-master)'
|
||||||
|
* bpf-master 2d311f480b52 [bpf/master] riscv, bpf: Fix patch_text implicit declaration
|
||||||
|
master c8ee37bde402 [bpf-next/master] libbpf: Fix bpf_xdp_query() in old kernels
|
||||||
|
$ git checkout bpf-master && git pull && git checkout master && git pull
|
||||||
|
...
|
||||||
|
$ git log --oneline -n1
|
||||||
|
c8ee37bde402 (HEAD -> master, bpf-next/master) libbpf: Fix bpf_xdp_query() in old kernels
|
||||||
|
$ cd ~/libbpf && git checkout master && git pull
|
||||||
|
Your branch is up to date with 'libbpf/master'.
|
||||||
|
Already up to date.
|
||||||
|
```
|
||||||
|
|
||||||
|
Running setup script
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
First step is to always run `sync-kernel.sh` script. It expects three arguments:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ scripts/sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, that we'll store script's entire output in `/tmp/libbpf-sync.txt` and
|
||||||
|
put it into PR summary later on. **Please store scripts output and include it
|
||||||
|
in PR summary for others to check for anything unexpected and suspicious.**
|
||||||
|
|
||||||
|
```
|
||||||
|
$ scripts/sync-kernel.sh ~/libbpf ~/linux bpf-master | tee /tmp/libbpf-sync.txt
|
||||||
|
Dumping existing libbpf commit signatures...
|
||||||
|
WORKDIR: /home/andriin/libbpf
|
||||||
|
LINUX REPO: /home/andriin/linux
|
||||||
|
LIBBPF REPO: /home/andriin/libbpf
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Most of the time this will go very uneventful. One expected case when sync
|
||||||
|
script might require user intervention is if `bpf` tree has some libbpf fixes,
|
||||||
|
which is nowadays not a very frequent occurence. But if that happens, script
|
||||||
|
will show you a diff between expected state as of latest bpf-next and synced
|
||||||
|
Github repo state. And will ask if these changes look good. Please use your
|
||||||
|
best judgement to verify that differences are indeed from expected `bpf` tree
|
||||||
|
fixes. E.g., it might look like below:
|
||||||
|
|
||||||
|
```
|
||||||
|
Comparing list of files...
|
||||||
|
Comparing file contents...
|
||||||
|
--- /home/andriin/linux/include/uapi/linux/netdev.h 2023-02-27 16:54:42.270583372 -0800
|
||||||
|
+++ /home/andriin/libbpf/include/uapi/linux/netdev.h 2023-02-27 16:54:34.615530796 -0800
|
||||||
|
@@ -19,7 +19,7 @@
|
||||||
|
* @NETDEV_XDP_ACT_XSK_ZEROCOPY: This feature informs if netdev supports AF_XDP
|
||||||
|
* in zero copy mode.
|
||||||
|
* @NETDEV_XDP_ACT_HW_OFFLOAD: This feature informs if netdev supports XDP hw
|
||||||
|
- * oflloading.
|
||||||
|
+ * offloading.
|
||||||
|
* @NETDEV_XDP_ACT_RX_SG: This feature informs if netdev implements non-linear
|
||||||
|
* XDP buffer support in the driver napi callback.
|
||||||
|
* @NETDEV_XDP_ACT_NDO_XMIT_SG: This feature informs if netdev implements
|
||||||
|
/home/andriin/linux/include/uapi/linux/netdev.h and /home/andriin/libbpf/include/uapi/linux/netdev.h are different!
|
||||||
|
Unfortunately, there are some inconsistencies, please double check.
|
||||||
|
Does everything look good? [y/N]:
|
||||||
|
```
|
||||||
|
|
||||||
|
If it looks sensible and expected, type `y` and script will proceed.
|
||||||
|
|
||||||
|
If sync is successful, your `~/linux` repo will be left in original state on
|
||||||
|
the original HEAD commit. `~/libbpf` repo will now be on a new branch, named
|
||||||
|
`libbpf-sync-<timestamp>` (e.g., `libbpf-sync-2023-02-28T00-53-40.072Z`).
|
||||||
|
|
||||||
|
Push this branch into your fork of `libbpf/libbpf` Github repo and create a PR:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push --set-upstream origin libbpf-sync-2023-02-28T00-53-40.072Z
|
||||||
|
Enumerating objects: 130, done.
|
||||||
|
Counting objects: 100% (115/115), done.
|
||||||
|
Delta compression using up to 80 threads
|
||||||
|
Compressing objects: 100% (28/28), done.
|
||||||
|
Writing objects: 100% (32/32), 5.57 KiB | 1.86 MiB/s, done.
|
||||||
|
Total 32 (delta 21), reused 0 (delta 0), pack-reused 0
|
||||||
|
remote: Resolving deltas: 100% (21/21), completed with 9 local objects.
|
||||||
|
remote:
|
||||||
|
remote: Create a pull request for 'libbpf-sync-2023-02-28T00-53-40.072Z' on GitHub by visiting:
|
||||||
|
remote: https://github.com/anakryiko/libbpf/pull/new/libbpf-sync-2023-02-28T00-53-40.072Z
|
||||||
|
remote:
|
||||||
|
To github.com:anakryiko/libbpf.git
|
||||||
|
* [new branch] libbpf-sync-2023-02-28T00-53-40.072Z -> libbpf-sync-2023-02-28T00-53-40.072Z
|
||||||
|
Branch 'libbpf-sync-2023-02-28T00-53-40.072Z' set up to track remote branch 'libbpf-sync-2023-02-28T00-53-40.072Z' from 'origin'.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Please, adjust PR name to have a properly looking timestamp. Libbpf
|
||||||
|
maintainers will be very thankful for that!**
|
||||||
|
|
||||||
|
By default Github will turn above branch name into PR with subject "Libbpf sync
|
||||||
|
2023 02 28 t00 53 40.072 z". Please fix this into a proper timestamp, e.g.:
|
||||||
|
"Libbpf sync 2023-02-28T00:53:40.072Z". Thank you!
|
||||||
|
|
||||||
|
**Please don't forget to paste contents of /tmp/libbpf-sync.txt into PR
|
||||||
|
summary!**
|
||||||
|
|
||||||
|
Once PR is created, libbpf CI will run a bunch of tests to check that
|
||||||
|
everything is good. In simple cases that would be all you'd need to do. In more
|
||||||
|
complicated cases some extra adjustments might be necessary.
|
||||||
|
|
||||||
|
**Please, keep naming and style consistent.** Prefix CI-related fixes with `ci: `
|
||||||
|
prefix. If you had to modify sync script, prefix it with `sync: `. Also make
|
||||||
|
sure that each such commit has `Signed-off-by: Your Full Name <your@email.com>`,
|
||||||
|
just like you'd do that for Linux upstream patch. Libbpf closely follows kernel
|
||||||
|
conventions and styling, so please help maintaining that.
|
||||||
|
|
||||||
|
Including new sources
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
If entirely new source files (typically `*.c`) were added to the library in the
|
||||||
|
kernel repository, it may be necessary to add these to the build system
|
||||||
|
manually (you may notice linker errors otherwise), because the script cannot
|
||||||
|
handle such changes automatically. To that end, edit `src/Makefile` as
|
||||||
|
necessary. Commit
|
||||||
|
[c2495832ced4](https://github.com/libbpf/libbpf/commit/c2495832ced4239bcd376b9954db38a6addd89ca)
|
||||||
|
is an example of how to go about doing that.
|
||||||
|
|
||||||
|
Similarly, if new public API header files were added, the `Makefile` will need
|
||||||
|
to be adjusted as well.
|
||||||
|
|
||||||
|
Updating allow/deny lists
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Libbpf CI intentionally runs a subset of latest BPF selftests on old kernel
|
||||||
|
(4.9 and 5.5, currently). It happens from time to time that some tests that
|
||||||
|
previously were successfully running on old kernels now don't, typically due to
|
||||||
|
reliance on some freshly added kernel feature. It might look something like this in [CI logs](https://github.com/libbpf/libbpf/actions/runs/4206303272/jobs/7299609578#step:4:2733):
|
||||||
|
|
||||||
|
```
|
||||||
|
All error logs:
|
||||||
|
serial_test_xdp_info:FAIL:get_xdp_none errno=2
|
||||||
|
#283 xdp_info:FAIL
|
||||||
|
Summary: 49/166 PASSED, 5 SKIPPED, 1 FAILED
|
||||||
|
```
|
||||||
|
|
||||||
|
In such case we can either work with upstream to fix test to be compatible with
|
||||||
|
old kernels, or we'll have to add a test into a denylist (or remove it from
|
||||||
|
allowlist, like was [done](https://github.com/libbpf/libbpf/commit/ea284299025bf85b85b4923191de6463cd43ccd6)
|
||||||
|
for the case above).
|
||||||
|
|
||||||
|
```
|
||||||
|
$ find . -name '*LIST*'
|
||||||
|
./ci/vmtest/configs/ALLOWLIST-4.9.0
|
||||||
|
./ci/vmtest/configs/DENYLIST-5.5.0
|
||||||
|
./ci/vmtest/configs/DENYLIST-latest.s390x
|
||||||
|
./ci/vmtest/configs/DENYLIST-latest
|
||||||
|
./ci/vmtest/configs/ALLOWLIST-5.5.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Please determine which tests need to be added/removed from which list. And then
|
||||||
|
add that as a separate commit. **Please keep using the same branch name, so
|
||||||
|
that the same PR can be updated.** There is no need to open new PRs for each
|
||||||
|
such fix.
|
||||||
|
|
||||||
|
Regenerating vmlinux.h header
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
To compile latest BPF selftests against old kernels, we check in pre-generated
|
||||||
|
[vmlinux.h](https://github.com/libbpf/libbpf/blob/master/.github/actions/build-selftests/vmlinux.h)
|
||||||
|
header file, located at `.github/actions/build-selftests/vmlinux.h`, which
|
||||||
|
contains type definitions from latest upstream kernel. When after libbpf sync
|
||||||
|
upstream BPF selftests require new kernel types, we'd need to regenerate
|
||||||
|
`vmlinux.h` and check it in as well.
|
||||||
|
|
||||||
|
This will looks something like this in [CI logs](https://github.com/libbpf/libbpf/actions/runs/4198939244/jobs/7283214243#step:4:1903):
|
||||||
|
|
||||||
|
```
|
||||||
|
In file included from progs/test_spin_lock_fail.c:5:
|
||||||
|
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:73:53: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||||
|
extern struct bpf_rb_node *bpf_rbtree_remove(struct bpf_rb_root *root,
|
||||||
|
^
|
||||||
|
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:81:35: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||||
|
extern void bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node,
|
||||||
|
^
|
||||||
|
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:90:52: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||||
|
extern struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root) __ksym;
|
||||||
|
^
|
||||||
|
3 errors generated.
|
||||||
|
make: *** [Makefile:572: /home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/test_spin_lock_fail.bpf.o] Error 1
|
||||||
|
make: *** Waiting for unfinished jobs....
|
||||||
|
Error: Process completed with exit code 2.
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll need to build latest upstream kernel from `bpf-next` tree, using BPF
|
||||||
|
selftest configs. Concat arch-agnostic and arch-specific configs, build kernel,
|
||||||
|
then use bpftool to dump `vmlinux.h`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd ~/linux
|
||||||
|
$ cat tools/testing/selftests/bpf/config \
|
||||||
|
tools/testing/selftests/bpf/config.x86_64 > .config
|
||||||
|
$ make -j$(nproc) olddefconfig all
|
||||||
|
...
|
||||||
|
$ bpftool btf dump file ~/linux/vmlinux format c > ~/libbpf/.github/actions/build-selftests/vmlinux.h
|
||||||
|
$ cd ~/libbpf && git add . && git commit -s
|
||||||
|
```
|
||||||
|
|
||||||
|
Check in generated `vmlinux.h`, don't forget to use `ci: ` commit prefix, add
|
||||||
|
it on top of sync commits. Push to Github and let libbpf CI do the checking for
|
||||||
|
you. See [this commit](https://github.com/libbpf/libbpf/commit/34212c94a64df8eeb1dd5d064630a65e1dfd4c20)
|
||||||
|
for reference.
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
---------------
|
||||||
|
|
||||||
|
If something goes wrong and sync script exits early or is terminated early by
|
||||||
|
user, you might end up with `~/linux` repo on temporary sync-related branch.
|
||||||
|
Don't worry, though, sync script never destroys repo state, it follows
|
||||||
|
"copy-on-write" philosophy and creates new branches where necessary. So it's
|
||||||
|
very easy to restore previous state. So if anything goes wrong, it's easy to
|
||||||
|
start fresh:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git branch | grep -E 'libbpf-.*Z'
|
||||||
|
libbpf-baseline-2023-02-28T00-43-35.146Z
|
||||||
|
libbpf-bpf-baseline-2023-02-28T00-43-35.146Z
|
||||||
|
libbpf-bpf-tip-2023-02-28T00-43-35.146Z
|
||||||
|
libbpf-squash-base-2023-02-28T00-43-35.146Z
|
||||||
|
* libbpf-squash-tip-2023-02-28T00-43-35.146Z
|
||||||
|
$ git cherry-pick --abort
|
||||||
|
$ git checkout master && git branch | grep -E 'libbpf-.*Z' | xargs git br -D
|
||||||
|
Switched to branch 'master'
|
||||||
|
Your branch is up to date with 'bpf-next/master'.
|
||||||
|
Deleted branch libbpf-baseline-2023-02-28T00-43-35.146Z (was 951bce29c898).
|
||||||
|
Deleted branch libbpf-bpf-baseline-2023-02-28T00-43-35.146Z (was 3a70e0d4c9d7).
|
||||||
|
Deleted branch libbpf-bpf-tip-2023-02-28T00-43-35.146Z (was 2d311f480b52).
|
||||||
|
Deleted branch libbpf-squash-base-2023-02-28T00-43-35.146Z (was 957f109ef883).
|
||||||
|
Deleted branch libbpf-squash-tip-2023-02-28T00-43-35.146Z (was be66130d2339).
|
||||||
|
Deleted branch libbpf-tip-2023-02-28T00-43-35.146Z (was 2d311f480b52).
|
||||||
|
```
|
||||||
|
|
||||||
|
You might need to do the same for your `~/libbpf` repo sometimes, depending at
|
||||||
|
which stage sync script was terminated.
|
||||||
BIN
assets/libbpf-logo-compact-darkbg.png
Normal file
|
After Width: | Height: | Size: 262 KiB |
BIN
assets/libbpf-logo-compact-mono.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
assets/libbpf-logo-compact.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
assets/libbpf-logo-sideways-darkbg.png
Normal file
|
After Width: | Height: | Size: 284 KiB |
BIN
assets/libbpf-logo-sideways-mono.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
assets/libbpf-logo-sideways.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
assets/libbpf-logo-sparse-darkbg.png
Normal file
|
After Width: | Height: | Size: 352 KiB |
BIN
assets/libbpf-logo-sparse-mono.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
assets/libbpf-logo-sparse.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
@@ -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,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,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
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
|
|||||||
ENV_VARS="${ENV_VARS:-}"
|
ENV_VARS="${ENV_VARS:-}"
|
||||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||||
ADDITIONAL_DEPS=(clang pkg-config gcc-10)
|
ADDITIONAL_DEPS=(pkgconf)
|
||||||
EXTRA_CFLAGS=""
|
EXTRA_CFLAGS=""
|
||||||
EXTRA_LDFLAGS=""
|
EXTRA_LDFLAGS=""
|
||||||
|
|
||||||
@@ -43,30 +43,35 @@ for phase in "${PHASES[@]}"; do
|
|||||||
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||||
docker_exec apt-get -y update
|
docker_exec apt-get -y update
|
||||||
docker_exec apt-get -y install aptitude
|
docker_exec apt-get -y install aptitude
|
||||||
docker_exec aptitude -y build-dep libelf-dev
|
docker_exec aptitude -y install make libz-dev libelf-dev
|
||||||
docker_exec aptitude -y install libelf-dev
|
|
||||||
docker_exec aptitude -y install "${ADDITIONAL_DEPS[@]}"
|
docker_exec aptitude -y install "${ADDITIONAL_DEPS[@]}"
|
||||||
echo -e "::endgroup::"
|
echo -e "::endgroup::"
|
||||||
;;
|
;;
|
||||||
RUN|RUN_CLANG|RUN_GCC10|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
RUN|RUN_CLANG|RUN_CLANG14|RUN_CLANG15|RUN_CLANG16|RUN_GCC10|RUN_GCC11|RUN_GCC12|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
||||||
CC="cc"
|
CC="cc"
|
||||||
if [[ "$phase" = *"CLANG"* ]]; then
|
if [[ "$phase" =~ "RUN_CLANG(\d+)(_ASAN)?" ]]; then
|
||||||
|
ENV_VARS="-e CC=clang-${BASH_REMATCH[1]} -e CXX=clang++-${BASH_REMATCH[1]}"
|
||||||
|
CC="clang-${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$phase" = *"CLANG"* ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
CC="clang"
|
CC="clang"
|
||||||
elif [[ "$phase" = *"GCC10"* ]]; then
|
elif [[ "$phase" =~ "RUN_GCC(\d+)(_ASAN)?" ]]; then
|
||||||
ENV_VARS="-e CC=gcc-10 -e CXX=g++-10"
|
ENV_VARS="-e CC=gcc-${BASH_REMATCH[1]} -e CXX=g++-${BASH_REMATCH[1]}"
|
||||||
CC="gcc-10"
|
CC="gcc-${BASH_REMATCH[1]}"
|
||||||
else
|
|
||||||
EXTRA_CFLAGS="${EXTRA_CFLAGS} -Wno-stringop-truncation"
|
|
||||||
fi
|
fi
|
||||||
if [[ "$phase" = *"ASAN"* ]]; then
|
if [[ "$phase" = *"ASAN"* ]]; then
|
||||||
EXTRA_CFLAGS="${EXTRA_CFLAGS} -fsanitize=address,undefined"
|
EXTRA_CFLAGS="${EXTRA_CFLAGS} -fsanitize=address,undefined"
|
||||||
EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -fsanitize=address,undefined"
|
EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -fsanitize=address,undefined"
|
||||||
fi
|
fi
|
||||||
|
if [[ "$CC" != "cc" ]]; then
|
||||||
|
docker_exec aptitude -y install "$CC"
|
||||||
|
else
|
||||||
|
docker_exec aptitude -y install gcc
|
||||||
|
fi
|
||||||
docker_exec mkdir build install
|
docker_exec mkdir build install
|
||||||
docker_exec ${CC} --version
|
docker_exec ${CC} --version
|
||||||
info "build"
|
info "build"
|
||||||
docker_exec make -j$((4*$(nproc))) EXTRA_CFLAGS="${EXTRA_CFLAGS}" EXTRA_LDFLAGS="${EXTRA_LDFLAGS}" -C ./src -B OBJDIR=../build
|
docker_exec make -j$((4*$(nproc))) EXTRA_CFLAGS="${EXTRA_CFLAGS}" EXTRA_LDFLAGS="${EXTRA_LDFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
info "ldd build/libbpf.so:"
|
info "ldd build/libbpf.so:"
|
||||||
docker_exec ldd build/libbpf.so
|
docker_exec ldd build/libbpf.so
|
||||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||||
@@ -76,7 +81,7 @@ for phase in "${PHASES[@]}"; do
|
|||||||
info "install"
|
info "install"
|
||||||
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||||
info "link binary"
|
info "link binary"
|
||||||
docker_exec bash -c "EXTRA_CFLAGS=\"${EXTRA_CFLAGS}\" EXTRA_LDFLAGS=\"${EXTRA_LDFLAGS}\" ./travis-ci/managers/test_compile.sh"
|
docker_exec bash -c "EXTRA_CFLAGS=\"${EXTRA_CFLAGS}\" EXTRA_LDFLAGS=\"${EXTRA_LDFLAGS}\" ./ci/managers/test_compile.sh"
|
||||||
;;
|
;;
|
||||||
CLEANUP)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
@@ -16,7 +16,6 @@ global_data
|
|||||||
global_data_init
|
global_data_init
|
||||||
global_func_args
|
global_func_args
|
||||||
hashmap
|
hashmap
|
||||||
l4lb_all
|
|
||||||
legacy_printk
|
legacy_printk
|
||||||
linked_funcs
|
linked_funcs
|
||||||
linked_maps
|
linked_maps
|
||||||
@@ -50,6 +49,5 @@ tcp_rtt
|
|||||||
tp_attach_query
|
tp_attach_query
|
||||||
usdt/urand_pid_attach
|
usdt/urand_pid_attach
|
||||||
xdp
|
xdp
|
||||||
xdp_info
|
|
||||||
xdp_noinline
|
xdp_noinline
|
||||||
xdp_perf
|
xdp_perf
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# This file is not used and is there for historic purposes only.
|
# This file is not used and is there for historic purposes only.
|
||||||
# See WHITELIST-5.5.0 instead.
|
# See ALLOWLIST-5.5.0 instead.
|
||||||
|
|
||||||
# PERMANENTLY DISABLED
|
# PERMANENTLY DISABLED
|
||||||
align # verifier output format changed
|
align # verifier output format changed
|
||||||
@@ -71,6 +71,7 @@ sk_lookup # v5.9+
|
|||||||
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
||||||
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
||||||
skb_helpers # helpers added in 5.8+
|
skb_helpers # helpers added in 5.8+
|
||||||
|
skeleton # creates too big ARRAY map
|
||||||
snprintf # v5.13+
|
snprintf # v5.13+
|
||||||
snprintf_btf # v5.10+
|
snprintf_btf # v5.10+
|
||||||
sock_fields # v5.10+
|
sock_fields # v5.10+
|
||||||
1
ci/vmtest/configs/DENYLIST-latest
Normal file
@@ -0,0 +1 @@
|
|||||||
|
decap_sanity # weird failure with decap_sanity_ns netns already existing, TBD
|
||||||
3
ci/vmtest/configs/DENYLIST-latest.s390x
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# TEMPORARY
|
||||||
|
usdt/basic # failing verifier due to bounds check after LLVM update
|
||||||
|
usdt/multispec # same as above
|
||||||
@@ -1,26 +1,20 @@
|
|||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
# $1 - start or end
|
# $1 - start or end
|
||||||
# $2 - fold identifier, no spaces
|
# $2 - fold identifier, no spaces
|
||||||
# $3 - fold section description
|
# $3 - fold section description
|
||||||
travis_fold() {
|
foldable() {
|
||||||
local YELLOW='\033[1;33m'
|
local YELLOW='\033[1;33m'
|
||||||
local NOCOLOR='\033[0m'
|
local NOCOLOR='\033[0m'
|
||||||
if [ -z ${GITHUB_WORKFLOW+x} ]; then
|
if [ $1 = "start" ]; then
|
||||||
echo travis_fold:$1:$2
|
line="::group::$2"
|
||||||
if [ ! -z "${3:-}" ]; then
|
if [ ! -z "${3:-}" ]; then
|
||||||
echo -e "${YELLOW}$3${NOCOLOR}"
|
line="$line - ${YELLOW}$3${NOCOLOR}"
|
||||||
fi
|
fi
|
||||||
echo
|
|
||||||
else
|
else
|
||||||
if [ $1 = "start" ]; then
|
line="::endgroup::"
|
||||||
line="::group::$2"
|
|
||||||
if [ ! -z "${3:-}" ]; then
|
|
||||||
line="$line - ${YELLOW}$3${NOCOLOR}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
line="::endgroup::"
|
|
||||||
fi
|
|
||||||
echo -e "$line"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "$line"
|
||||||
}
|
}
|
||||||
|
|
||||||
__print() {
|
__print() {
|
||||||
87
ci/vmtest/run_selftests.sh
Executable file
@@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||||
|
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
|
||||||
|
STATUS_FILE=/exitstatus
|
||||||
|
|
||||||
|
read_lists() {
|
||||||
|
(for path in "$@"; do
|
||||||
|
if [[ -s "$path" ]]; then
|
||||||
|
cat "$path"
|
||||||
|
fi;
|
||||||
|
done) | cut -d'#' -f1 | tr -s ' \t\n' ','
|
||||||
|
}
|
||||||
|
|
||||||
|
test_progs() {
|
||||||
|
if [[ "${KERNEL}" != '4.9.0' ]]; then
|
||||||
|
foldable start test_progs "Testing test_progs"
|
||||||
|
# "&& true" does not change the return code (it is not executed
|
||||||
|
# if the Python script fails), but it prevents exiting on a
|
||||||
|
# failure due to the "set -e".
|
||||||
|
./test_progs ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
||||||
|
echo "test_progs:$?" >> "${STATUS_FILE}"
|
||||||
|
foldable end test_progs
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_progs_no_alu32() {
|
||||||
|
foldable start test_progs-no_alu32 "Testing test_progs-no_alu32"
|
||||||
|
./test_progs-no_alu32 ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
||||||
|
echo "test_progs-no_alu32:$?" >> "${STATUS_FILE}"
|
||||||
|
foldable end test_progs-no_alu32
|
||||||
|
}
|
||||||
|
|
||||||
|
test_maps() {
|
||||||
|
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||||
|
foldable start test_maps "Testing test_maps"
|
||||||
|
./test_maps && true
|
||||||
|
echo "test_maps:$?" >> "${STATUS_FILE}"
|
||||||
|
foldable end test_maps
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_verifier() {
|
||||||
|
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||||
|
foldable start test_verifier "Testing test_verifier"
|
||||||
|
./test_verifier && true
|
||||||
|
echo "test_verifier:$?" >> "${STATUS_FILE}"
|
||||||
|
foldable end test_verifier
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
foldable end vm_init
|
||||||
|
|
||||||
|
configs_path=/${PROJECT_NAME}/selftests/bpf
|
||||||
|
local_configs_path=${PROJECT_NAME}/vmtest/configs
|
||||||
|
DENYLIST=$(read_lists \
|
||||||
|
"$configs_path/DENYLIST" \
|
||||||
|
"$configs_path/DENYLIST.${ARCH}" \
|
||||||
|
"$local_configs_path/DENYLIST-${KERNEL}" \
|
||||||
|
"$local_configs_path/DENYLIST-${KERNEL}.${ARCH}" \
|
||||||
|
)
|
||||||
|
ALLOWLIST=$(read_lists \
|
||||||
|
"$configs_path/ALLOWLIST" \
|
||||||
|
"$configs_path/ALLOWLIST.${ARCH}" \
|
||||||
|
"$local_configs_path/ALLOWLIST-${KERNEL}" \
|
||||||
|
"$local_configs_path/ALLOWLIST-${KERNEL}.${ARCH}" \
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "DENYLIST: ${DENYLIST}"
|
||||||
|
echo "ALLOWLIST: ${ALLOWLIST}"
|
||||||
|
|
||||||
|
cd ${PROJECT_NAME}/selftests/bpf
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
test_progs
|
||||||
|
test_progs_no_alu32
|
||||||
|
# test_maps
|
||||||
|
test_verifier
|
||||||
|
else
|
||||||
|
for test_name in "$@"; do
|
||||||
|
"${test_name}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
@@ -1,21 +1,33 @@
|
|||||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
.. _libbpf:
|
||||||
|
|
||||||
|
======
|
||||||
libbpf
|
libbpf
|
||||||
======
|
======
|
||||||
|
|
||||||
|
If you are looking to develop BPF applications using the libbpf library, this
|
||||||
|
directory contains important documentation that you should read.
|
||||||
|
|
||||||
|
To get started, it is recommended to begin with the :doc:`libbpf Overview
|
||||||
|
<libbpf_overview>` document, which provides a high-level understanding of the
|
||||||
|
libbpf APIs and their usage. This will give you a solid foundation to start
|
||||||
|
exploring and utilizing the various features of libbpf to develop your BPF
|
||||||
|
applications.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
libbpf_overview
|
||||||
API Documentation <https://libbpf.readthedocs.io/en/latest/api.html>
|
API Documentation <https://libbpf.readthedocs.io/en/latest/api.html>
|
||||||
|
program_types
|
||||||
libbpf_naming_convention
|
libbpf_naming_convention
|
||||||
libbpf_build
|
libbpf_build
|
||||||
|
|
||||||
This is documentation for libbpf, a userspace library for loading and
|
|
||||||
interacting with bpf programs.
|
|
||||||
|
|
||||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
All general BPF questions, including kernel functionality, libbpf APIs and their
|
||||||
their application, should be sent to bpf@vger.kernel.org mailing list.
|
application, should be sent to bpf@vger.kernel.org mailing list. You can
|
||||||
You can `subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the
|
`subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the mailing list
|
||||||
mailing list search its `archive <https://lore.kernel.org/bpf/>`_.
|
search its `archive <https://lore.kernel.org/bpf/>`_. Please search the archive
|
||||||
Please search the archive before asking new questions. It very well might
|
before asking new questions. It may be that this was already addressed or
|
||||||
be that this was already addressed or answered before.
|
answered before.
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ described here. It's recommended to follow these conventions whenever a
|
|||||||
new function or type is added to keep libbpf API clean and consistent.
|
new function or type is added to keep libbpf API clean and consistent.
|
||||||
|
|
||||||
All types and functions provided by libbpf API should have one of the
|
All types and functions provided by libbpf API should have one of the
|
||||||
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
|
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``btf_dump_``,
|
||||||
``btf_dump_``, ``ring_buffer_``, ``perf_buffer_``.
|
``ring_buffer_``, ``perf_buffer_``.
|
||||||
|
|
||||||
System call wrappers
|
System call wrappers
|
||||||
--------------------
|
--------------------
|
||||||
@@ -59,15 +59,6 @@ Auxiliary functions and types that don't fit well in any of categories
|
|||||||
described above should have ``libbpf_`` prefix, e.g.
|
described above should have ``libbpf_`` prefix, e.g.
|
||||||
``libbpf_get_error`` or ``libbpf_prog_type_by_name``.
|
``libbpf_get_error`` or ``libbpf_prog_type_by_name``.
|
||||||
|
|
||||||
AF_XDP functions
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
AF_XDP functions should have an ``xsk_`` prefix, e.g.
|
|
||||||
``xsk_umem__get_data`` or ``xsk_umem__create``. The interface consists
|
|
||||||
of both low-level ring access functions and high-level configuration
|
|
||||||
functions. These can be mixed and matched. Note that these functions
|
|
||||||
are not reentrant for performance reasons.
|
|
||||||
|
|
||||||
ABI
|
ABI
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -92,8 +83,8 @@ This prevents from accidentally exporting a symbol, that is not supposed
|
|||||||
to be a part of ABI what, in turn, improves both libbpf developer- and
|
to be a part of ABI what, in turn, improves both libbpf developer- and
|
||||||
user-experiences.
|
user-experiences.
|
||||||
|
|
||||||
ABI versionning
|
ABI versioning
|
||||||
---------------
|
--------------
|
||||||
|
|
||||||
To make future ABI extensions possible libbpf ABI is versioned.
|
To make future ABI extensions possible libbpf ABI is versioned.
|
||||||
Versioning is implemented by ``libbpf.map`` version script that is
|
Versioning is implemented by ``libbpf.map`` version script that is
|
||||||
@@ -157,7 +148,7 @@ API documentation convention
|
|||||||
The libbpf API is documented via comments above definitions in
|
The libbpf API is documented via comments above definitions in
|
||||||
header files. These comments can be rendered by doxygen and sphinx
|
header files. These comments can be rendered by doxygen and sphinx
|
||||||
for well organized html output. This section describes the
|
for well organized html output. This section describes the
|
||||||
convention in which these comments should be formated.
|
convention in which these comments should be formatted.
|
||||||
|
|
||||||
Here is an example from btf.h:
|
Here is an example from btf.h:
|
||||||
|
|
||||||
|
|||||||
228
docs/libbpf_overview.rst
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
===============
|
||||||
|
libbpf Overview
|
||||||
|
===============
|
||||||
|
|
||||||
|
libbpf is a C-based library containing a BPF loader that takes compiled BPF
|
||||||
|
object files and prepares and loads them into the Linux kernel. libbpf takes the
|
||||||
|
heavy lifting of loading, verifying, and attaching BPF programs to various
|
||||||
|
kernel hooks, allowing BPF application developers to focus only on BPF program
|
||||||
|
correctness and performance.
|
||||||
|
|
||||||
|
The following are the high-level features supported by libbpf:
|
||||||
|
|
||||||
|
* Provides high-level and low-level APIs for user space programs to interact
|
||||||
|
with BPF programs. The low-level APIs wrap all the bpf system call
|
||||||
|
functionality, which is useful when users need more fine-grained control
|
||||||
|
over the interactions between user space and BPF programs.
|
||||||
|
* Provides overall support for the BPF object skeleton generated by bpftool.
|
||||||
|
The skeleton file simplifies the process for the user space programs to access
|
||||||
|
global variables and work with BPF programs.
|
||||||
|
* Provides BPF-side APIS, including BPF helper definitions, BPF maps support,
|
||||||
|
and tracing helpers, allowing developers to simplify BPF code writing.
|
||||||
|
* Supports BPF CO-RE mechanism, enabling BPF developers to write portable
|
||||||
|
BPF programs that can be compiled once and run across different kernel
|
||||||
|
versions.
|
||||||
|
|
||||||
|
This document will delve into the above concepts in detail, providing a deeper
|
||||||
|
understanding of the capabilities and advantages of libbpf and how it can help
|
||||||
|
you develop BPF applications efficiently.
|
||||||
|
|
||||||
|
BPF App Lifecycle and libbpf APIs
|
||||||
|
==================================
|
||||||
|
|
||||||
|
A BPF application consists of one or more BPF programs (either cooperating or
|
||||||
|
completely independent), BPF maps, and global variables. The global
|
||||||
|
variables are shared between all BPF programs, which allows them to cooperate on
|
||||||
|
a common set of data. libbpf provides APIs that user space programs can use to
|
||||||
|
manipulate the BPF programs by triggering different phases of a BPF application
|
||||||
|
lifecycle.
|
||||||
|
|
||||||
|
The following section provides a brief overview of each phase in the BPF life
|
||||||
|
cycle:
|
||||||
|
|
||||||
|
* **Open phase**: In this phase, libbpf parses the BPF
|
||||||
|
object file and discovers BPF maps, BPF programs, and global variables. After
|
||||||
|
a BPF app is opened, user space apps can make additional adjustments
|
||||||
|
(setting BPF program types, if necessary; pre-setting initial values for
|
||||||
|
global variables, etc.) before all the entities are created and loaded.
|
||||||
|
|
||||||
|
* **Load phase**: In the load phase, libbpf creates BPF
|
||||||
|
maps, resolves various relocations, and verifies and loads BPF programs into
|
||||||
|
the kernel. At this point, libbpf validates all the parts of a BPF application
|
||||||
|
and loads the BPF program into the kernel, but no BPF program has yet been
|
||||||
|
executed. After the load phase, it’s possible to set up the initial BPF map
|
||||||
|
state without racing with the BPF program code execution.
|
||||||
|
|
||||||
|
* **Attachment phase**: In this phase, libbpf
|
||||||
|
attaches BPF programs to various BPF hook points (e.g., tracepoints, kprobes,
|
||||||
|
cgroup hooks, network packet processing pipeline, etc.). During this
|
||||||
|
phase, BPF programs perform useful work such as processing
|
||||||
|
packets, or updating BPF maps and global variables that can be read from user
|
||||||
|
space.
|
||||||
|
|
||||||
|
* **Tear down phase**: In the tear down phase,
|
||||||
|
libbpf detaches BPF programs and unloads them from the kernel. BPF maps are
|
||||||
|
destroyed, and all the resources used by the BPF app are freed.
|
||||||
|
|
||||||
|
BPF Object Skeleton File
|
||||||
|
========================
|
||||||
|
|
||||||
|
BPF skeleton is an alternative interface to libbpf APIs for working with BPF
|
||||||
|
objects. Skeleton code abstract away generic libbpf APIs to significantly
|
||||||
|
simplify code for manipulating BPF programs from user space. Skeleton code
|
||||||
|
includes a bytecode representation of the BPF object file, simplifying the
|
||||||
|
process of distributing your BPF code. With BPF bytecode embedded, there are no
|
||||||
|
extra files to deploy along with your application binary.
|
||||||
|
|
||||||
|
You can generate the skeleton header file ``(.skel.h)`` for a specific object
|
||||||
|
file by passing the BPF object to the bpftool. The generated BPF skeleton
|
||||||
|
provides the following custom functions that correspond to the BPF lifecycle,
|
||||||
|
each of them prefixed with the specific object name:
|
||||||
|
|
||||||
|
* ``<name>__open()`` – creates and opens BPF application (``<name>`` stands for
|
||||||
|
the specific bpf object name)
|
||||||
|
* ``<name>__load()`` – instantiates, loads,and verifies BPF application parts
|
||||||
|
* ``<name>__attach()`` – attaches all auto-attachable BPF programs (it’s
|
||||||
|
optional, you can have more control by using libbpf APIs directly)
|
||||||
|
* ``<name>__destroy()`` – detaches all BPF programs and
|
||||||
|
frees up all used resources
|
||||||
|
|
||||||
|
Using the skeleton code is the recommended way to work with bpf programs. Keep
|
||||||
|
in mind, BPF skeleton provides access to the underlying BPF object, so whatever
|
||||||
|
was possible to do with generic libbpf APIs is still possible even when the BPF
|
||||||
|
skeleton is used. It's an additive convenience feature, with no syscalls, and no
|
||||||
|
cumbersome code.
|
||||||
|
|
||||||
|
Other Advantages of Using Skeleton File
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
* BPF skeleton provides an interface for user space programs to work with BPF
|
||||||
|
global variables. The skeleton code memory maps global variables as a struct
|
||||||
|
into user space. The struct interface allows user space programs to initialize
|
||||||
|
BPF programs before the BPF load phase and fetch and update data from user
|
||||||
|
space afterward.
|
||||||
|
|
||||||
|
* The ``skel.h`` file reflects the object file structure by listing out the
|
||||||
|
available maps, programs, etc. BPF skeleton provides direct access to all the
|
||||||
|
BPF maps and BPF programs as struct fields. This eliminates the need for
|
||||||
|
string-based lookups with ``bpf_object_find_map_by_name()`` and
|
||||||
|
``bpf_object_find_program_by_name()`` APIs, reducing errors due to BPF source
|
||||||
|
code and user-space code getting out of sync.
|
||||||
|
|
||||||
|
* The embedded bytecode representation of the object file ensures that the
|
||||||
|
skeleton and the BPF object file are always in sync.
|
||||||
|
|
||||||
|
BPF Helpers
|
||||||
|
===========
|
||||||
|
|
||||||
|
libbpf provides BPF-side APIs that BPF programs can use to interact with the
|
||||||
|
system. The BPF helpers definition allows developers to use them in BPF code as
|
||||||
|
any other plain C function. For example, there are helper functions to print
|
||||||
|
debugging messages, get the time since the system was booted, interact with BPF
|
||||||
|
maps, manipulate network packets, etc.
|
||||||
|
|
||||||
|
For a complete description of what the helpers do, the arguments they take, and
|
||||||
|
the return value, see the `bpf-helpers
|
||||||
|
<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>`_ man page.
|
||||||
|
|
||||||
|
BPF CO-RE (Compile Once – Run Everywhere)
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
BPF programs work in the kernel space and have access to kernel memory and data
|
||||||
|
structures. One limitation that BPF applications come across is the lack of
|
||||||
|
portability across different kernel versions and configurations. `BCC
|
||||||
|
<https://github.com/iovisor/bcc/>`_ is one of the solutions for BPF
|
||||||
|
portability. However, it comes with runtime overhead and a large binary size
|
||||||
|
from embedding the compiler with the application.
|
||||||
|
|
||||||
|
libbpf steps up the BPF program portability by supporting the BPF CO-RE concept.
|
||||||
|
BPF CO-RE brings together BTF type information, libbpf, and the compiler to
|
||||||
|
produce a single executable binary that you can run on multiple kernel versions
|
||||||
|
and configurations.
|
||||||
|
|
||||||
|
To make BPF programs portable libbpf relies on the BTF type information of the
|
||||||
|
running kernel. Kernel also exposes this self-describing authoritative BTF
|
||||||
|
information through ``sysfs`` at ``/sys/kernel/btf/vmlinux``.
|
||||||
|
|
||||||
|
You can generate the BTF information for the running kernel with the following
|
||||||
|
command:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
||||||
|
|
||||||
|
The command generates a ``vmlinux.h`` header file with all kernel types
|
||||||
|
(:doc:`BTF types <../btf>`) that the running kernel uses. Including
|
||||||
|
``vmlinux.h`` in your BPF program eliminates dependency on system-wide kernel
|
||||||
|
headers.
|
||||||
|
|
||||||
|
libbpf enables portability of BPF programs by looking at the BPF program’s
|
||||||
|
recorded BTF type and relocation information and matching them to BTF
|
||||||
|
information (vmlinux) provided by the running kernel. libbpf then resolves and
|
||||||
|
matches all the types and fields, and updates necessary offsets and other
|
||||||
|
relocatable data to ensure that BPF program’s logic functions correctly for a
|
||||||
|
specific kernel on the host. BPF CO-RE concept thus eliminates overhead
|
||||||
|
associated with BPF development and allows developers to write portable BPF
|
||||||
|
applications without modifications and runtime source code compilation on the
|
||||||
|
target machine.
|
||||||
|
|
||||||
|
The following code snippet shows how to read the parent field of a kernel
|
||||||
|
``task_struct`` using BPF CO-RE and libbf. The basic helper to read a field in a
|
||||||
|
CO-RE relocatable manner is ``bpf_core_read(dst, sz, src)``, which will read
|
||||||
|
``sz`` bytes from the field referenced by ``src`` into the memory pointed to by
|
||||||
|
``dst``.
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
:emphasize-lines: 6
|
||||||
|
|
||||||
|
//...
|
||||||
|
struct task_struct *task = (void *)bpf_get_current_task();
|
||||||
|
struct task_struct *parent_task;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bpf_core_read(&parent_task, sizeof(void *), &task->parent);
|
||||||
|
if (err) {
|
||||||
|
/* handle error */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parent_task contains the value of task->parent pointer */
|
||||||
|
|
||||||
|
In the code snippet, we first get a pointer to the current ``task_struct`` using
|
||||||
|
``bpf_get_current_task()``. We then use ``bpf_core_read()`` to read the parent
|
||||||
|
field of task struct into the ``parent_task`` variable. ``bpf_core_read()`` is
|
||||||
|
just like ``bpf_probe_read_kernel()`` BPF helper, except it records information
|
||||||
|
about the field that should be relocated on the target kernel. i.e, if the
|
||||||
|
``parent`` field gets shifted to a different offset within
|
||||||
|
``struct task_struct`` due to some new field added in front of it, libbpf will
|
||||||
|
automatically adjust the actual offset to the proper value.
|
||||||
|
|
||||||
|
Getting Started with libbpf
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Check out the `libbpf-bootstrap <https://github.com/libbpf/libbpf-bootstrap>`_
|
||||||
|
repository with simple examples of using libbpf to build various BPF
|
||||||
|
applications.
|
||||||
|
|
||||||
|
See also `libbpf API documentation
|
||||||
|
<https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||||
|
|
||||||
|
libbpf and Rust
|
||||||
|
===============
|
||||||
|
|
||||||
|
If you are building BPF applications in Rust, it is recommended to use the
|
||||||
|
`Libbpf-rs <https://github.com/libbpf/libbpf-rs>`_ library instead of bindgen
|
||||||
|
bindings directly to libbpf. Libbpf-rs wraps libbpf functionality in
|
||||||
|
Rust-idiomatic interfaces and provides libbpf-cargo plugin to handle BPF code
|
||||||
|
compilation and skeleton generation. Using Libbpf-rs will make building user
|
||||||
|
space part of the BPF application easier. Note that the BPF program themselves
|
||||||
|
must still be written in plain C.
|
||||||
|
|
||||||
|
Additional Documentation
|
||||||
|
========================
|
||||||
|
|
||||||
|
* `Program types and ELF Sections <https://libbpf.readthedocs.io/en/latest/program_types.html>`_
|
||||||
|
* `API naming convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html>`_
|
||||||
|
* `Building libbpf <https://libbpf.readthedocs.io/en/latest/libbpf_build.html>`_
|
||||||
|
* `API documentation Convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html#api-documentation-convention>`_
|
||||||
203
docs/program_types.rst
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
.. _program_types_and_elf:
|
||||||
|
|
||||||
|
Program Types and ELF Sections
|
||||||
|
==============================
|
||||||
|
|
||||||
|
The table below lists the program types, their attach types where relevant and the ELF section
|
||||||
|
names supported by libbpf for them. The ELF section names follow these rules:
|
||||||
|
|
||||||
|
- ``type`` is an exact match, e.g. ``SEC("socket")``
|
||||||
|
- ``type+`` means it can be either exact ``SEC("type")`` or well-formed ``SEC("type/extras")``
|
||||||
|
with a '``/``' separator between ``type`` and ``extras``.
|
||||||
|
|
||||||
|
When ``extras`` are specified, they provide details of how to auto-attach the BPF program. The
|
||||||
|
format of ``extras`` depends on the program type, e.g. ``SEC("tracepoint/<category>/<name>")``
|
||||||
|
for tracepoints or ``SEC("usdt/<path>:<provider>:<name>")`` for USDT probes. The extras are
|
||||||
|
described in more detail in the footnotes.
|
||||||
|
|
||||||
|
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| Program Type | Attach Type | ELF Section Name | Sleepable |
|
||||||
|
+===========================================+========================================+==================================+===========+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_DEVICE`` | ``BPF_CGROUP_DEVICE`` | ``cgroup/dev`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_SKB`` | | ``cgroup/skb`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET_EGRESS`` | ``cgroup_skb/egress`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET_INGRESS`` | ``cgroup_skb/ingress`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_SOCKOPT`` | ``BPF_CGROUP_GETSOCKOPT`` | ``cgroup/getsockopt`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_SETSOCKOPT`` | ``cgroup/setsockopt`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_SOCK_ADDR`` | ``BPF_CGROUP_INET4_BIND`` | ``cgroup/bind4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET4_CONNECT`` | ``cgroup/connect4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET4_GETPEERNAME`` | ``cgroup/getpeername4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET4_GETSOCKNAME`` | ``cgroup/getsockname4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET6_BIND`` | ``cgroup/bind6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET6_CONNECT`` | ``cgroup/connect6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET6_GETPEERNAME`` | ``cgroup/getpeername6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET6_GETSOCKNAME`` | ``cgroup/getsockname6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_UDP4_RECVMSG`` | ``cgroup/recvmsg4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_UDP4_SENDMSG`` | ``cgroup/sendmsg4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET6_POST_BIND`` | ``cgroup/post_bind6`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET_SOCK_CREATE`` | ``cgroup/sock_create`` | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``cgroup/sock`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_CGROUP_INET_SOCK_RELEASE`` | ``cgroup/sock_release`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_CGROUP_SYSCTL`` | ``BPF_CGROUP_SYSCTL`` | ``cgroup/sysctl`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_EXT`` | | ``freplace+`` [#fentry]_ | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_FLOW_DISSECTOR`` | ``BPF_FLOW_DISSECTOR`` | ``flow_dissector`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_KPROBE`` | | ``kprobe+`` [#kprobe]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``kretprobe+`` [#kprobe]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``ksyscall+`` [#ksyscall]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``kretsyscall+`` [#ksyscall]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``uprobe+`` [#uprobe]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``uprobe.s+`` [#uprobe]_ | Yes |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``uretprobe+`` [#uprobe]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``uretprobe.s+`` [#uprobe]_ | Yes |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``usdt+`` [#usdt]_ | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_TRACE_KPROBE_MULTI`` | ``kprobe.multi+`` [#kpmulti]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``kretprobe.multi+`` [#kpmulti]_ | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LIRC_MODE2`` | ``BPF_LIRC_MODE2`` | ``lirc_mode2`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LSM`` | ``BPF_LSM_CGROUP`` | ``lsm_cgroup+`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_LSM_MAC`` | ``lsm+`` [#lsm]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``lsm.s+`` [#lsm]_ | Yes |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LWT_IN`` | | ``lwt_in`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LWT_OUT`` | | ``lwt_out`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LWT_SEG6LOCAL`` | | ``lwt_seg6local`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_LWT_XMIT`` | | ``lwt_xmit`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_PERF_EVENT`` | | ``perf_event`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE`` | | ``raw_tp.w+`` [#rawtp]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``raw_tracepoint.w+`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_RAW_TRACEPOINT`` | | ``raw_tp+`` [#rawtp]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``raw_tracepoint+`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SCHED_ACT`` | | ``action`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SCHED_CLS`` | | ``classifier`` | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``tc`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SK_LOOKUP`` | ``BPF_SK_LOOKUP`` | ``sk_lookup`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SK_MSG`` | ``BPF_SK_MSG_VERDICT`` | ``sk_msg`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SK_REUSEPORT`` | ``BPF_SK_REUSEPORT_SELECT_OR_MIGRATE`` | ``sk_reuseport/migrate`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_SK_REUSEPORT_SELECT`` | ``sk_reuseport`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SK_SKB`` | | ``sk_skb`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_SK_SKB_STREAM_PARSER`` | ``sk_skb/stream_parser`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_SK_SKB_STREAM_VERDICT`` | ``sk_skb/stream_verdict`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SOCKET_FILTER`` | | ``socket`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SOCK_OPS`` | ``BPF_CGROUP_SOCK_OPS`` | ``sockops`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_STRUCT_OPS`` | | ``struct_ops+`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_SYSCALL`` | | ``syscall`` | Yes |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_TRACEPOINT`` | | ``tp+`` [#tp]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``tracepoint+`` [#tp]_ | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_TRACING`` | ``BPF_MODIFY_RETURN`` | ``fmod_ret+`` [#fentry]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``fmod_ret.s+`` [#fentry]_ | Yes |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_TRACE_FENTRY`` | ``fentry+`` [#fentry]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``fentry.s+`` [#fentry]_ | Yes |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_TRACE_FEXIT`` | ``fexit+`` [#fentry]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``fexit.s+`` [#fentry]_ | Yes |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_TRACE_ITER`` | ``iter+`` [#iter]_ | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``iter.s+`` [#iter]_ | Yes |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_TRACE_RAW_TP`` | ``tp_btf+`` [#fentry]_ | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
| ``BPF_PROG_TYPE_XDP`` | ``BPF_XDP_CPUMAP`` | ``xdp.frags/cpumap`` | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``xdp/cpumap`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_XDP_DEVMAP`` | ``xdp.frags/devmap`` | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``xdp/devmap`` | |
|
||||||
|
+ +----------------------------------------+----------------------------------+-----------+
|
||||||
|
| | ``BPF_XDP`` | ``xdp.frags`` | |
|
||||||
|
+ + +----------------------------------+-----------+
|
||||||
|
| | | ``xdp`` | |
|
||||||
|
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||||
|
|
||||||
|
|
||||||
|
.. rubric:: Footnotes
|
||||||
|
|
||||||
|
.. [#fentry] The ``fentry`` attach format is ``fentry[.s]/<function>``.
|
||||||
|
.. [#kprobe] The ``kprobe`` attach format is ``kprobe/<function>[+<offset>]``. Valid
|
||||||
|
characters for ``function`` are ``a-zA-Z0-9_.`` and ``offset`` must be a valid
|
||||||
|
non-negative integer.
|
||||||
|
.. [#ksyscall] The ``ksyscall`` attach format is ``ksyscall/<syscall>``.
|
||||||
|
.. [#uprobe] The ``uprobe`` attach format is ``uprobe[.s]/<path>:<function>[+<offset>]``.
|
||||||
|
.. [#usdt] The ``usdt`` attach format is ``usdt/<path>:<provider>:<name>``.
|
||||||
|
.. [#kpmulti] The ``kprobe.multi`` attach format is ``kprobe.multi/<pattern>`` where ``pattern``
|
||||||
|
supports ``*`` and ``?`` wildcards. Valid characters for pattern are
|
||||||
|
``a-zA-Z0-9_.*?``.
|
||||||
|
.. [#lsm] The ``lsm`` attachment format is ``lsm[.s]/<hook>``.
|
||||||
|
.. [#rawtp] The ``raw_tp`` attach format is ``raw_tracepoint[.w]/<tracepoint>``.
|
||||||
|
.. [#tp] The ``tracepoint`` attach format is ``tracepoint/<category>/<name>``.
|
||||||
|
.. [#iter] The ``iter`` attach format is ``iter[.s]/<struct-name>``.
|
||||||
115
include/uapi/linux/fcntl.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
|
#ifndef _UAPI_LINUX_FCNTL_H
|
||||||
|
#define _UAPI_LINUX_FCNTL_H
|
||||||
|
|
||||||
|
#include <asm/fcntl.h>
|
||||||
|
#include <linux/openat2.h>
|
||||||
|
|
||||||
|
#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0)
|
||||||
|
#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cancel a blocking posix lock; internal use only until we expose an
|
||||||
|
* asynchronous lock api to userspace:
|
||||||
|
*/
|
||||||
|
#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5)
|
||||||
|
|
||||||
|
/* Create a file descriptor with FD_CLOEXEC set. */
|
||||||
|
#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request nofications on a directory.
|
||||||
|
* See below for events that may be notified.
|
||||||
|
*/
|
||||||
|
#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set and get of pipe page size array
|
||||||
|
*/
|
||||||
|
#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
|
||||||
|
#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set/Get seals
|
||||||
|
*/
|
||||||
|
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
|
||||||
|
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types of seals
|
||||||
|
*/
|
||||||
|
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
|
||||||
|
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
|
||||||
|
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
|
||||||
|
#define F_SEAL_WRITE 0x0008 /* prevent writes */
|
||||||
|
#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */
|
||||||
|
#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */
|
||||||
|
/* (1U << 31) is reserved for signed error codes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set/Get write life time hints. {GET,SET}_RW_HINT operate on the
|
||||||
|
* underlying inode, while {GET,SET}_FILE_RW_HINT operate only on
|
||||||
|
* the specific file.
|
||||||
|
*/
|
||||||
|
#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11)
|
||||||
|
#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12)
|
||||||
|
#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13)
|
||||||
|
#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
|
||||||
|
* used to clear any hints previously set.
|
||||||
|
*/
|
||||||
|
#define RWH_WRITE_LIFE_NOT_SET 0
|
||||||
|
#define RWH_WRITE_LIFE_NONE 1
|
||||||
|
#define RWH_WRITE_LIFE_SHORT 2
|
||||||
|
#define RWH_WRITE_LIFE_MEDIUM 3
|
||||||
|
#define RWH_WRITE_LIFE_LONG 4
|
||||||
|
#define RWH_WRITE_LIFE_EXTREME 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The originally introduced spelling is remained from the first
|
||||||
|
* versions of the patch set that introduced the feature, see commit
|
||||||
|
* v4.13-rc1~212^2~51.
|
||||||
|
*/
|
||||||
|
#define RWF_WRITE_LIFE_NOT_SET RWH_WRITE_LIFE_NOT_SET
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types of directory notifications that may be requested.
|
||||||
|
*/
|
||||||
|
#define DN_ACCESS 0x00000001 /* File accessed */
|
||||||
|
#define DN_MODIFY 0x00000002 /* File modified */
|
||||||
|
#define DN_CREATE 0x00000004 /* File created */
|
||||||
|
#define DN_DELETE 0x00000008 /* File removed */
|
||||||
|
#define DN_RENAME 0x00000010 /* File renamed */
|
||||||
|
#define DN_ATTRIB 0x00000020 /* File changed attibutes */
|
||||||
|
#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
|
||||||
|
* meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
|
||||||
|
* unlinkat. The two functions do completely different things and therefore,
|
||||||
|
* the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
|
||||||
|
* faccessat would be undefined behavior and thus treating it equivalent to
|
||||||
|
* AT_EACCESS is valid undefined behavior.
|
||||||
|
*/
|
||||||
|
#define AT_FDCWD -100 /* Special value used to indicate
|
||||||
|
openat should use the current
|
||||||
|
working directory. */
|
||||||
|
#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
|
||||||
|
#define AT_EACCESS 0x200 /* Test access permitted for
|
||||||
|
effective IDs, not real IDs. */
|
||||||
|
#define AT_REMOVEDIR 0x200 /* Remove directory instead of
|
||||||
|
unlinking file. */
|
||||||
|
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
|
||||||
|
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
|
||||||
|
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
|
||||||
|
|
||||||
|
#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */
|
||||||
|
#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */
|
||||||
|
#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */
|
||||||
|
#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */
|
||||||
|
|
||||||
|
#define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
|
||||||
|
|
||||||
|
#endif /* _UAPI_LINUX_FCNTL_H */
|
||||||
@@ -605,6 +605,7 @@ enum {
|
|||||||
IFLA_MACVLAN_MACADDR_COUNT,
|
IFLA_MACVLAN_MACADDR_COUNT,
|
||||||
IFLA_MACVLAN_BC_QUEUE_LEN,
|
IFLA_MACVLAN_BC_QUEUE_LEN,
|
||||||
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
|
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
|
||||||
|
IFLA_MACVLAN_BC_CUTOFF,
|
||||||
__IFLA_MACVLAN_MAX,
|
__IFLA_MACVLAN_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -673,6 +674,7 @@ enum {
|
|||||||
IFLA_XFRM_UNSPEC,
|
IFLA_XFRM_UNSPEC,
|
||||||
IFLA_XFRM_LINK,
|
IFLA_XFRM_LINK,
|
||||||
IFLA_XFRM_IF_ID,
|
IFLA_XFRM_IF_ID,
|
||||||
|
IFLA_XFRM_COLLECT_METADATA,
|
||||||
__IFLA_XFRM_MAX
|
__IFLA_XFRM_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -890,6 +892,7 @@ enum {
|
|||||||
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
|
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
|
||||||
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
|
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
|
||||||
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
|
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
|
||||||
|
IFLA_BOND_SLAVE_PRIO,
|
||||||
__IFLA_BOND_SLAVE_MAX,
|
__IFLA_BOND_SLAVE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
61
include/uapi/linux/netdev.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||||
|
/* Do not edit directly, auto-generated from: */
|
||||||
|
/* Documentation/netlink/specs/netdev.yaml */
|
||||||
|
/* YNL-GEN uapi header */
|
||||||
|
|
||||||
|
#ifndef _UAPI_LINUX_NETDEV_H
|
||||||
|
#define _UAPI_LINUX_NETDEV_H
|
||||||
|
|
||||||
|
#define NETDEV_FAMILY_NAME "netdev"
|
||||||
|
#define NETDEV_FAMILY_VERSION 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum netdev_xdp_act
|
||||||
|
* @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
|
||||||
|
* ndo_xdp_xmit callback.
|
||||||
|
* @NETDEV_XDP_ACT_XSK_ZEROCOPY: This feature informs if netdev supports AF_XDP
|
||||||
|
* in zero copy mode.
|
||||||
|
* @NETDEV_XDP_ACT_HW_OFFLOAD: This feature informs if netdev supports XDP hw
|
||||||
|
* offloading.
|
||||||
|
* @NETDEV_XDP_ACT_RX_SG: This feature informs if netdev implements non-linear
|
||||||
|
* XDP buffer support in the driver napi callback.
|
||||||
|
* @NETDEV_XDP_ACT_NDO_XMIT_SG: This feature informs if netdev implements
|
||||||
|
* non-linear XDP buffer support in ndo_xdp_xmit callback.
|
||||||
|
*/
|
||||||
|
enum netdev_xdp_act {
|
||||||
|
NETDEV_XDP_ACT_BASIC = 1,
|
||||||
|
NETDEV_XDP_ACT_REDIRECT = 2,
|
||||||
|
NETDEV_XDP_ACT_NDO_XMIT = 4,
|
||||||
|
NETDEV_XDP_ACT_XSK_ZEROCOPY = 8,
|
||||||
|
NETDEV_XDP_ACT_HW_OFFLOAD = 16,
|
||||||
|
NETDEV_XDP_ACT_RX_SG = 32,
|
||||||
|
NETDEV_XDP_ACT_NDO_XMIT_SG = 64,
|
||||||
|
|
||||||
|
NETDEV_XDP_ACT_MASK = 127,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NETDEV_A_DEV_IFINDEX = 1,
|
||||||
|
NETDEV_A_DEV_PAD,
|
||||||
|
NETDEV_A_DEV_XDP_FEATURES,
|
||||||
|
|
||||||
|
__NETDEV_A_DEV_MAX,
|
||||||
|
NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_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_MAX,
|
||||||
|
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NETDEV_MCGRP_MGMT "mgmt"
|
||||||
|
|
||||||
|
#endif /* _UAPI_LINUX_NETDEV_H */
|
||||||
43
include/uapi/linux/openat2.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
|
#ifndef _UAPI_LINUX_OPENAT2_H
|
||||||
|
#define _UAPI_LINUX_OPENAT2_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arguments for how openat2(2) should open the target path. If only @flags and
|
||||||
|
* @mode are non-zero, then openat2(2) operates very similarly to openat(2).
|
||||||
|
*
|
||||||
|
* However, unlike openat(2), unknown or invalid bits in @flags result in
|
||||||
|
* -EINVAL rather than being silently ignored. @mode must be zero unless one of
|
||||||
|
* {O_CREAT, O_TMPFILE} are set.
|
||||||
|
*
|
||||||
|
* @flags: O_* flags.
|
||||||
|
* @mode: O_CREAT/O_TMPFILE file mode.
|
||||||
|
* @resolve: RESOLVE_* flags.
|
||||||
|
*/
|
||||||
|
struct open_how {
|
||||||
|
__u64 flags;
|
||||||
|
__u64 mode;
|
||||||
|
__u64 resolve;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* how->resolve flags for openat2(2). */
|
||||||
|
#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
|
||||||
|
(includes bind-mounts). */
|
||||||
|
#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
|
||||||
|
"magic-links". */
|
||||||
|
#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
|
||||||
|
(implies OEXT_NO_MAGICLINKS) */
|
||||||
|
#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
|
||||||
|
"..", symlinks, and absolute
|
||||||
|
paths which escape the dirfd. */
|
||||||
|
#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
|
||||||
|
be scoped inside the dirfd
|
||||||
|
(similar to chroot(2)). */
|
||||||
|
#define RESOLVE_CACHED 0x20 /* Only complete if resolution can be
|
||||||
|
completed through cached lookup. May
|
||||||
|
return -EAGAIN if that's not
|
||||||
|
possible. */
|
||||||
|
|
||||||
|
#endif /* _UAPI_LINUX_OPENAT2_H */
|
||||||
@@ -164,8 +164,6 @@ enum perf_event_sample_format {
|
|||||||
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
|
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
|
||||||
|
|
||||||
PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
|
PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
|
||||||
|
|
||||||
__PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
|
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
|
||||||
@@ -204,6 +202,8 @@ enum perf_branch_sample_type_shift {
|
|||||||
|
|
||||||
PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, /* save low level index of raw branch records */
|
PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, /* save low level index of raw branch records */
|
||||||
|
|
||||||
|
PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */
|
||||||
|
|
||||||
PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
|
PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -233,6 +233,8 @@ enum perf_branch_sample_type {
|
|||||||
|
|
||||||
PERF_SAMPLE_BRANCH_HW_INDEX = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT,
|
PERF_SAMPLE_BRANCH_HW_INDEX = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT,
|
||||||
|
|
||||||
|
PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,
|
||||||
|
|
||||||
PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
|
PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -253,9 +255,48 @@ enum {
|
|||||||
PERF_BR_COND_RET = 10, /* conditional function return */
|
PERF_BR_COND_RET = 10, /* conditional function return */
|
||||||
PERF_BR_ERET = 11, /* exception return */
|
PERF_BR_ERET = 11, /* exception return */
|
||||||
PERF_BR_IRQ = 12, /* irq */
|
PERF_BR_IRQ = 12, /* irq */
|
||||||
|
PERF_BR_SERROR = 13, /* system error */
|
||||||
|
PERF_BR_NO_TX = 14, /* not in transaction */
|
||||||
|
PERF_BR_EXTEND_ABI = 15, /* extend ABI */
|
||||||
PERF_BR_MAX,
|
PERF_BR_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common branch speculation outcome classification
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
PERF_BR_SPEC_NA = 0, /* Not available */
|
||||||
|
PERF_BR_SPEC_WRONG_PATH = 1, /* Speculative but on wrong path */
|
||||||
|
PERF_BR_NON_SPEC_CORRECT_PATH = 2, /* Non-speculative but on correct path */
|
||||||
|
PERF_BR_SPEC_CORRECT_PATH = 3, /* Speculative and on correct path */
|
||||||
|
PERF_BR_SPEC_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PERF_BR_NEW_FAULT_ALGN = 0, /* Alignment fault */
|
||||||
|
PERF_BR_NEW_FAULT_DATA = 1, /* Data fault */
|
||||||
|
PERF_BR_NEW_FAULT_INST = 2, /* Inst fault */
|
||||||
|
PERF_BR_NEW_ARCH_1 = 3, /* Architecture specific */
|
||||||
|
PERF_BR_NEW_ARCH_2 = 4, /* Architecture specific */
|
||||||
|
PERF_BR_NEW_ARCH_3 = 5, /* Architecture specific */
|
||||||
|
PERF_BR_NEW_ARCH_4 = 6, /* Architecture specific */
|
||||||
|
PERF_BR_NEW_ARCH_5 = 7, /* Architecture specific */
|
||||||
|
PERF_BR_NEW_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PERF_BR_PRIV_UNKNOWN = 0,
|
||||||
|
PERF_BR_PRIV_USER = 1,
|
||||||
|
PERF_BR_PRIV_KERNEL = 2,
|
||||||
|
PERF_BR_PRIV_HV = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PERF_BR_ARM64_FIQ PERF_BR_NEW_ARCH_1
|
||||||
|
#define PERF_BR_ARM64_DEBUG_HALT PERF_BR_NEW_ARCH_2
|
||||||
|
#define PERF_BR_ARM64_DEBUG_EXIT PERF_BR_NEW_ARCH_3
|
||||||
|
#define PERF_BR_ARM64_DEBUG_INST PERF_BR_NEW_ARCH_4
|
||||||
|
#define PERF_BR_ARM64_DEBUG_DATA PERF_BR_NEW_ARCH_5
|
||||||
|
|
||||||
#define PERF_SAMPLE_BRANCH_PLM_ALL \
|
#define PERF_SAMPLE_BRANCH_PLM_ALL \
|
||||||
(PERF_SAMPLE_BRANCH_USER|\
|
(PERF_SAMPLE_BRANCH_USER|\
|
||||||
PERF_SAMPLE_BRANCH_KERNEL|\
|
PERF_SAMPLE_BRANCH_KERNEL|\
|
||||||
@@ -301,6 +342,7 @@ enum {
|
|||||||
* { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
|
* { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
|
||||||
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
|
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
|
||||||
* { u64 id; } && PERF_FORMAT_ID
|
* { u64 id; } && PERF_FORMAT_ID
|
||||||
|
* { u64 lost; } && PERF_FORMAT_LOST
|
||||||
* } && !PERF_FORMAT_GROUP
|
* } && !PERF_FORMAT_GROUP
|
||||||
*
|
*
|
||||||
* { u64 nr;
|
* { u64 nr;
|
||||||
@@ -308,6 +350,7 @@ enum {
|
|||||||
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
|
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
|
||||||
* { u64 value;
|
* { u64 value;
|
||||||
* { u64 id; } && PERF_FORMAT_ID
|
* { u64 id; } && PERF_FORMAT_ID
|
||||||
|
* { u64 lost; } && PERF_FORMAT_LOST
|
||||||
* } cntr[nr];
|
* } cntr[nr];
|
||||||
* } && PERF_FORMAT_GROUP
|
* } && PERF_FORMAT_GROUP
|
||||||
* };
|
* };
|
||||||
@@ -317,8 +360,9 @@ enum perf_event_read_format {
|
|||||||
PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
|
PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
|
||||||
PERF_FORMAT_ID = 1U << 2,
|
PERF_FORMAT_ID = 1U << 2,
|
||||||
PERF_FORMAT_GROUP = 1U << 3,
|
PERF_FORMAT_GROUP = 1U << 3,
|
||||||
|
PERF_FORMAT_LOST = 1U << 4,
|
||||||
|
|
||||||
PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
|
PERF_FORMAT_MAX = 1U << 5, /* non-ABI */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
|
#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
|
||||||
@@ -330,6 +374,7 @@ enum perf_event_read_format {
|
|||||||
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
|
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
|
||||||
#define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */
|
#define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */
|
||||||
#define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */
|
#define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */
|
||||||
|
#define PERF_ATTR_SIZE_VER8 136 /* add: config3 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hardware event_id to monitor via a performance monitoring event:
|
* Hardware event_id to monitor via a performance monitoring event:
|
||||||
@@ -471,6 +516,8 @@ struct perf_event_attr {
|
|||||||
* truncated accordingly on 32 bit architectures.
|
* truncated accordingly on 32 bit architectures.
|
||||||
*/
|
*/
|
||||||
__u64 sig_data;
|
__u64 sig_data;
|
||||||
|
|
||||||
|
__u64 config3; /* extension of config2 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -491,7 +538,7 @@ struct perf_event_query_bpf {
|
|||||||
/*
|
/*
|
||||||
* User provided buffer to store program ids
|
* User provided buffer to store program ids
|
||||||
*/
|
*/
|
||||||
__u32 ids[0];
|
__u32 ids[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1292,7 +1339,9 @@ union perf_mem_data_src {
|
|||||||
#define PERF_MEM_LVLNUM_L2 0x02 /* L2 */
|
#define PERF_MEM_LVLNUM_L2 0x02 /* L2 */
|
||||||
#define PERF_MEM_LVLNUM_L3 0x03 /* L3 */
|
#define PERF_MEM_LVLNUM_L3 0x03 /* L3 */
|
||||||
#define PERF_MEM_LVLNUM_L4 0x04 /* L4 */
|
#define PERF_MEM_LVLNUM_L4 0x04 /* L4 */
|
||||||
/* 5-0xa available */
|
/* 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 */
|
#define PERF_MEM_LVLNUM_ANY_CACHE 0x0b /* Any cache */
|
||||||
#define PERF_MEM_LVLNUM_LFB 0x0c /* LFB */
|
#define PERF_MEM_LVLNUM_LFB 0x0c /* LFB */
|
||||||
#define PERF_MEM_LVLNUM_RAM 0x0d /* RAM */
|
#define PERF_MEM_LVLNUM_RAM 0x0d /* RAM */
|
||||||
@@ -1310,7 +1359,7 @@ union perf_mem_data_src {
|
|||||||
#define PERF_MEM_SNOOP_SHIFT 19
|
#define PERF_MEM_SNOOP_SHIFT 19
|
||||||
|
|
||||||
#define PERF_MEM_SNOOPX_FWD 0x01 /* forward */
|
#define PERF_MEM_SNOOPX_FWD 0x01 /* forward */
|
||||||
/* 1 free */
|
#define PERF_MEM_SNOOPX_PEER 0x02 /* xfer from peer */
|
||||||
#define PERF_MEM_SNOOPX_SHIFT 38
|
#define PERF_MEM_SNOOPX_SHIFT 38
|
||||||
|
|
||||||
/* locked instruction */
|
/* locked instruction */
|
||||||
@@ -1360,6 +1409,7 @@ union perf_mem_data_src {
|
|||||||
* abort: aborting a hardware transaction
|
* abort: aborting a hardware transaction
|
||||||
* cycles: cycles from last branch (or 0 if not supported)
|
* cycles: cycles from last branch (or 0 if not supported)
|
||||||
* type: branch type
|
* type: branch type
|
||||||
|
* spec: branch speculation info (or 0 if not supported)
|
||||||
*/
|
*/
|
||||||
struct perf_branch_entry {
|
struct perf_branch_entry {
|
||||||
__u64 from;
|
__u64 from;
|
||||||
@@ -1370,7 +1420,10 @@ struct perf_branch_entry {
|
|||||||
abort:1, /* transaction abort */
|
abort:1, /* transaction abort */
|
||||||
cycles:16, /* cycle count to last branch */
|
cycles:16, /* cycle count to last branch */
|
||||||
type:4, /* branch type */
|
type:4, /* branch type */
|
||||||
reserved:40;
|
spec:2, /* branch speculation info */
|
||||||
|
new_type:4, /* additional branch type */
|
||||||
|
priv:3, /* privilege level */
|
||||||
|
reserved:31;
|
||||||
};
|
};
|
||||||
|
|
||||||
union perf_sample_weight {
|
union perf_sample_weight {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ struct tc_u32_sel {
|
|||||||
|
|
||||||
short hoff;
|
short hoff;
|
||||||
__be32 hmask;
|
__be32 hmask;
|
||||||
struct tc_u32_key keys[0];
|
struct tc_u32_key keys[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tc_u32_mark {
|
struct tc_u32_mark {
|
||||||
@@ -192,7 +192,7 @@ struct tc_u32_mark {
|
|||||||
struct tc_u32_pcnt {
|
struct tc_u32_pcnt {
|
||||||
__u64 rcnt;
|
__u64 rcnt;
|
||||||
__u64 rhit;
|
__u64 rhit;
|
||||||
__u64 kcnts[0];
|
__u64 kcnts[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ rm -rf elfutils
|
|||||||
git clone git://sourceware.org/git/elfutils.git
|
git clone git://sourceware.org/git/elfutils.git
|
||||||
(
|
(
|
||||||
cd elfutils
|
cd elfutils
|
||||||
git checkout 83251d4091241acddbdcf16f814e3bc6ef3df49a
|
git checkout e9f3045caa5c4498f371383e5519151942d48b6d
|
||||||
git log --oneline -1
|
git log --oneline -1
|
||||||
|
|
||||||
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
||||||
|
|||||||
@@ -42,8 +42,11 @@ PATH_MAP=( \
|
|||||||
[tools/include/uapi/linux/bpf_common.h]=include/uapi/linux/bpf_common.h \
|
[tools/include/uapi/linux/bpf_common.h]=include/uapi/linux/bpf_common.h \
|
||||||
[tools/include/uapi/linux/bpf.h]=include/uapi/linux/bpf.h \
|
[tools/include/uapi/linux/bpf.h]=include/uapi/linux/bpf.h \
|
||||||
[tools/include/uapi/linux/btf.h]=include/uapi/linux/btf.h \
|
[tools/include/uapi/linux/btf.h]=include/uapi/linux/btf.h \
|
||||||
|
[tools/include/uapi/linux/fcntl.h]=include/uapi/linux/fcntl.h \
|
||||||
|
[tools/include/uapi/linux/openat2.h]=include/uapi/linux/openat2.h \
|
||||||
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||||
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||||
|
[tools/include/uapi/linux/netdev.h]=include/uapi/linux/netdev.h \
|
||||||
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||||
[tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
|
[tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
|
||||||
[tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
|
[tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
|
||||||
@@ -51,8 +54,8 @@ PATH_MAP=( \
|
|||||||
[Documentation/bpf/libbpf]=docs \
|
[Documentation/bpf/libbpf]=docs \
|
||||||
)
|
)
|
||||||
|
|
||||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
|
LIBBPF_PATHS=("${!PATH_MAP[@]}" ":^tools/lib/bpf/Makefile" ":^tools/lib/bpf/Build" ":^tools/lib/bpf/.gitignore" ":^tools/include/tools/libc_compat.h")
|
||||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
LIBBPF_VIEW_PATHS=("${PATH_MAP[@]}")
|
||||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
|
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
|
||||||
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
||||||
|
|
||||||
@@ -85,7 +88,9 @@ commit_desc()
|
|||||||
# $2 - paths filter
|
# $2 - paths filter
|
||||||
commit_signature()
|
commit_signature()
|
||||||
{
|
{
|
||||||
git show --pretty='("%s")|%aI|%b' --shortstat $1 -- ${2-.} | tr '\n' '|'
|
local ref=$1
|
||||||
|
shift
|
||||||
|
git show --pretty='("%s")|%aI|%b' --shortstat $ref -- "${@-.}" | tr '\n' '|'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cherry-pick commits touching libbpf-related files
|
# Cherry-pick commits touching libbpf-related files
|
||||||
@@ -104,7 +109,7 @@ cherry_pick_commits()
|
|||||||
local libbpf_conflict_cnt
|
local libbpf_conflict_cnt
|
||||||
local desc
|
local desc
|
||||||
|
|
||||||
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} -- "${LIBBPF_PATHS[@]}")
|
||||||
for new_commit in ${new_commits}; do
|
for new_commit in ${new_commits}; do
|
||||||
desc="$(commit_desc ${new_commit})"
|
desc="$(commit_desc ${new_commit})"
|
||||||
signature="$(commit_signature ${new_commit} "${LIBBPF_PATHS[@]}")"
|
signature="$(commit_signature ${new_commit} "${LIBBPF_PATHS[@]}")"
|
||||||
@@ -138,7 +143,7 @@ cherry_pick_commits()
|
|||||||
echo "Picking '${desc}'..."
|
echo "Picking '${desc}'..."
|
||||||
if ! git cherry-pick ${new_commit} &>/dev/null; then
|
if ! git cherry-pick ${new_commit} &>/dev/null; then
|
||||||
echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
|
echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
|
||||||
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
|
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- "${LIBBPF_PATHS[@]}" | wc -l)
|
||||||
conflict_cnt=$(git diff --name-only | wc -l)
|
conflict_cnt=$(git diff --name-only | wc -l)
|
||||||
prompt_resolution=1
|
prompt_resolution=1
|
||||||
|
|
||||||
@@ -257,7 +262,7 @@ if ((${COMMIT_CNT} <= 0)); then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Exclude baseline commit and generate nice cover letter with summary
|
# Exclude baseline commit and generate nice cover letter with summary
|
||||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
git format-patch --no-signature ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
||||||
|
|
||||||
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
||||||
cd_to ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
@@ -284,7 +289,7 @@ cd_to ${LIBBPF_REPO}
|
|||||||
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
||||||
if ((${helpers_changes} == 1)); then
|
if ((${helpers_changes} == 1)); then
|
||||||
git add src/bpf_helper_defs.h
|
git add src/bpf_helper_defs.h
|
||||||
git commit -m "sync: auto-generate latest BPF helpers
|
git commit -s -m "sync: auto-generate latest BPF helpers
|
||||||
|
|
||||||
Latest changes to BPF helper definitions.
|
Latest changes to BPF helper definitions.
|
||||||
" -- src/bpf_helper_defs.h
|
" -- src/bpf_helper_defs.h
|
||||||
@@ -306,7 +311,7 @@ Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
|
|||||||
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
||||||
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
||||||
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
||||||
git commit --file=-
|
git commit -s --file=-
|
||||||
|
|
||||||
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
||||||
|
|
||||||
@@ -316,10 +321,10 @@ cd_to ${LINUX_REPO}
|
|||||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
|
git ls-files -- "${LIBBPF_VIEW_PATHS[@]}" | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
|
||||||
|
|
||||||
cd_to ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
git ls-files -- "${LIBBPF_VIEW_PATHS[@]}" | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
||||||
|
|
||||||
echo "Comparing list of files..."
|
echo "Comparing list of files..."
|
||||||
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
LIBBPF_MAJOR_VERSION := 1
|
LIBBPF_MAJOR_VERSION := 1
|
||||||
LIBBPF_MINOR_VERSION := 0
|
LIBBPF_MINOR_VERSION := 2
|
||||||
LIBBPF_PATCH_VERSION := 0
|
LIBBPF_PATCH_VERSION := 0
|
||||||
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
||||||
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
||||||
@@ -52,7 +52,7 @@ STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
|||||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.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 \
|
btf_dump.o hashmap.o ringbuf.o strset.o linker.o gen_loader.o \
|
||||||
relo_core.o usdt.o
|
relo_core.o usdt.o zip.o
|
||||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||||
|
|
||||||
@@ -77,7 +77,8 @@ INSTALL = install
|
|||||||
|
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
|
|
||||||
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(shell uname -m)),)
|
HOSTARCH = $(firstword $(subst -, ,$(shell $(CC) -dumpmachine)))
|
||||||
|
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(HOSTARCH)),)
|
||||||
LIBSUBDIR := lib64
|
LIBSUBDIR := lib64
|
||||||
else
|
else
|
||||||
LIBSUBDIR := lib
|
LIBSUBDIR := lib
|
||||||
|
|||||||
300
src/bpf.c
@@ -84,9 +84,7 @@ static inline int sys_bpf_fd(enum bpf_cmd cmd, union bpf_attr *attr,
|
|||||||
return ensure_good_fd(fd);
|
return ensure_good_fd(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROG_LOAD_ATTEMPTS 5
|
int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts)
|
||||||
|
|
||||||
static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts)
|
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -107,7 +105,7 @@ static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int
|
|||||||
*/
|
*/
|
||||||
int probe_memcg_account(void)
|
int probe_memcg_account(void)
|
||||||
{
|
{
|
||||||
const size_t prog_load_attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd);
|
const size_t attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd);
|
||||||
struct bpf_insn insns[] = {
|
struct bpf_insn insns[] = {
|
||||||
BPF_EMIT_CALL(BPF_FUNC_ktime_get_coarse_ns),
|
BPF_EMIT_CALL(BPF_FUNC_ktime_get_coarse_ns),
|
||||||
BPF_EXIT_INSN(),
|
BPF_EXIT_INSN(),
|
||||||
@@ -117,13 +115,13 @@ int probe_memcg_account(void)
|
|||||||
int prog_fd;
|
int prog_fd;
|
||||||
|
|
||||||
/* attempt loading freplace trying to use custom BTF */
|
/* attempt loading freplace trying to use custom BTF */
|
||||||
memset(&attr, 0, prog_load_attr_sz);
|
memset(&attr, 0, attr_sz);
|
||||||
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||||
attr.insns = ptr_to_u64(insns);
|
attr.insns = ptr_to_u64(insns);
|
||||||
attr.insn_cnt = insn_cnt;
|
attr.insn_cnt = insn_cnt;
|
||||||
attr.license = ptr_to_u64("GPL");
|
attr.license = ptr_to_u64("GPL");
|
||||||
|
|
||||||
prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, prog_load_attr_sz);
|
prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, attr_sz);
|
||||||
if (prog_fd >= 0) {
|
if (prog_fd >= 0) {
|
||||||
close(prog_fd);
|
close(prog_fd);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -183,7 +181,7 @@ int bpf_map_create(enum bpf_map_type map_type,
|
|||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
attr.map_type = map_type;
|
attr.map_type = map_type;
|
||||||
if (map_name)
|
if (map_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||||
libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
|
libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
|
||||||
attr.key_size = key_size;
|
attr.key_size = key_size;
|
||||||
attr.value_size = value_size;
|
attr.value_size = value_size;
|
||||||
@@ -232,8 +230,9 @@ alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
|||||||
int bpf_prog_load(enum bpf_prog_type prog_type,
|
int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||||
const char *prog_name, const char *license,
|
const char *prog_name, const char *license,
|
||||||
const struct bpf_insn *insns, size_t insn_cnt,
|
const struct bpf_insn *insns, size_t insn_cnt,
|
||||||
const struct bpf_prog_load_opts *opts)
|
struct bpf_prog_load_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, log_true_size);
|
||||||
void *finfo = NULL, *linfo = NULL;
|
void *finfo = NULL, *linfo = NULL;
|
||||||
const char *func_info, *line_info;
|
const char *func_info, *line_info;
|
||||||
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
||||||
@@ -253,7 +252,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
if (attempts == 0)
|
if (attempts == 0)
|
||||||
attempts = PROG_LOAD_ATTEMPTS;
|
attempts = PROG_LOAD_ATTEMPTS;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
|
||||||
attr.prog_type = prog_type;
|
attr.prog_type = prog_type;
|
||||||
attr.expected_attach_type = OPTS_GET(opts, expected_attach_type, 0);
|
attr.expected_attach_type = OPTS_GET(opts, expected_attach_type, 0);
|
||||||
@@ -263,7 +262,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0);
|
attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0);
|
||||||
attr.kern_version = OPTS_GET(opts, kern_version, 0);
|
attr.kern_version = OPTS_GET(opts, kern_version, 0);
|
||||||
|
|
||||||
if (prog_name)
|
if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||||
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
|
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
|
||||||
attr.license = ptr_to_u64(license);
|
attr.license = ptr_to_u64(license);
|
||||||
|
|
||||||
@@ -291,10 +290,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
|
|
||||||
if (!!log_buf != !!log_size)
|
if (!!log_buf != !!log_size)
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
if (log_level > (4 | 2 | 1))
|
|
||||||
return libbpf_err(-EINVAL);
|
|
||||||
if (log_level && !log_buf)
|
|
||||||
return libbpf_err(-EINVAL);
|
|
||||||
|
|
||||||
func_info_rec_size = OPTS_GET(opts, func_info_rec_size, 0);
|
func_info_rec_size = OPTS_GET(opts, func_info_rec_size, 0);
|
||||||
func_info = OPTS_GET(opts, func_info, NULL);
|
func_info = OPTS_GET(opts, func_info, NULL);
|
||||||
@@ -316,7 +311,8 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
attr.log_level = log_level;
|
attr.log_level = log_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||||
|
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
@@ -356,7 +352,8 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||||
|
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -370,7 +367,8 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
|||||||
attr.log_size = log_size;
|
attr.log_size = log_size;
|
||||||
attr.log_level = 1;
|
attr.log_level = 1;
|
||||||
|
|
||||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||||
|
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
/* free() doesn't affect errno, so we don't need to restore it */
|
/* free() doesn't affect errno, so we don't need to restore it */
|
||||||
@@ -382,127 +380,136 @@ done:
|
|||||||
int bpf_map_update_elem(int fd, const void *key, const void *value,
|
int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||||
__u64 flags)
|
__u64 flags)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_elem(int fd, const void *key, void *value)
|
int bpf_map_lookup_elem(int fd, const void *key, void *value)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
int bpf_map_lookup_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_delete_elem(int fd, const void *key)
|
int bpf_map_delete_elem(int fd, const void *key)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_delete_elem_flags(int fd, const void *key, __u64 flags)
|
int bpf_map_delete_elem_flags(int fd, const void *key, __u64 flags)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_get_next_key(int fd, const void *key, void *next_key)
|
int bpf_map_get_next_key(int fd, const void *key, void *next_key)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, next_key);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.next_key = ptr_to_u64(next_key);
|
attr.next_key = ptr_to_u64(next_key);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_freeze(int fd)
|
int bpf_map_freeze(int fd)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, map_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_FREEZE, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,13 +518,14 @@ static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
|||||||
__u32 *count,
|
__u32 *count,
|
||||||
const struct bpf_map_batch_opts *opts)
|
const struct bpf_map_batch_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, batch);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_map_batch_opts))
|
if (!OPTS_VALID(opts, bpf_map_batch_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.batch.map_fd = fd;
|
attr.batch.map_fd = fd;
|
||||||
attr.batch.in_batch = ptr_to_u64(in_batch);
|
attr.batch.in_batch = ptr_to_u64(in_batch);
|
||||||
attr.batch.out_batch = ptr_to_u64(out_batch);
|
attr.batch.out_batch = ptr_to_u64(out_batch);
|
||||||
@@ -527,7 +535,7 @@ static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
|||||||
attr.batch.elem_flags = OPTS_GET(opts, elem_flags, 0);
|
attr.batch.elem_flags = OPTS_GET(opts, elem_flags, 0);
|
||||||
attr.batch.flags = OPTS_GET(opts, flags, 0);
|
attr.batch.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
ret = sys_bpf(cmd, &attr, sizeof(attr));
|
ret = sys_bpf(cmd, &attr, attr_sz);
|
||||||
*count = attr.batch.count;
|
*count = attr.batch.count;
|
||||||
|
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
@@ -566,26 +574,37 @@ int bpf_map_update_batch(int fd, const void *keys, const void *values, __u32 *co
|
|||||||
|
|
||||||
int bpf_obj_pin(int fd, const char *pathname)
|
int bpf_obj_pin(int fd, const char *pathname)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
attr.bpf_fd = fd;
|
attr.bpf_fd = fd;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_OBJ_PIN, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_obj_get(const char *pathname)
|
int bpf_obj_get(const char *pathname)
|
||||||
{
|
{
|
||||||
|
return bpf_obj_get_opts(pathname, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
if (!OPTS_VALID(opts, bpf_obj_get_opts))
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_OBJ_GET, &attr, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
|
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
||||||
|
|
||||||
|
fd = sys_bpf_fd(BPF_OBJ_GET, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,52 +622,50 @@ int bpf_prog_attach_opts(int prog_fd, int target_fd,
|
|||||||
enum bpf_attach_type type,
|
enum bpf_attach_type type,
|
||||||
const struct bpf_prog_attach_opts *opts)
|
const struct bpf_prog_attach_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
attr.attach_bpf_fd = prog_fd;
|
attr.attach_bpf_fd = prog_fd;
|
||||||
attr.attach_type = type;
|
attr.attach_type = type;
|
||||||
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
||||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_ATTACH, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((alias("bpf_prog_attach_opts")))
|
|
||||||
int bpf_prog_attach_xattr(int prog_fd, int target_fd,
|
|
||||||
enum bpf_attach_type type,
|
|
||||||
const struct bpf_prog_attach_opts *opts);
|
|
||||||
|
|
||||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
attr.attach_type = type;
|
attr.attach_type = type;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
attr.attach_bpf_fd = prog_fd;
|
attr.attach_bpf_fd = prog_fd;
|
||||||
attr.attach_type = type;
|
attr.attach_type = type;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,6 +673,7 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
enum bpf_attach_type attach_type,
|
enum bpf_attach_type attach_type,
|
||||||
const struct bpf_link_create_opts *opts)
|
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;
|
__u32 target_btf_id, iter_info_len;
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd, err;
|
int fd, err;
|
||||||
@@ -674,7 +692,7 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.link_create.prog_fd = prog_fd;
|
attr.link_create.prog_fd = prog_fd;
|
||||||
attr.link_create.target_fd = target_fd;
|
attr.link_create.target_fd = target_fd;
|
||||||
attr.link_create.attach_type = attach_type;
|
attr.link_create.attach_type = attach_type;
|
||||||
@@ -718,7 +736,7 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
proceed:
|
proceed:
|
||||||
fd = sys_bpf_fd(BPF_LINK_CREATE, &attr, sizeof(attr));
|
fd = sys_bpf_fd(BPF_LINK_CREATE, &attr, attr_sz);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
/* we'll get EINVAL if LINK_CREATE doesn't support attaching fentry
|
/* we'll get EINVAL if LINK_CREATE doesn't support attaching fentry
|
||||||
@@ -754,44 +772,53 @@ proceed:
|
|||||||
|
|
||||||
int bpf_link_detach(int link_fd)
|
int bpf_link_detach(int link_fd)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, link_detach);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.link_detach.link_fd = link_fd;
|
attr.link_detach.link_fd = link_fd;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_LINK_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_LINK_DETACH, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_update(int link_fd, int new_prog_fd,
|
int bpf_link_update(int link_fd, int new_prog_fd,
|
||||||
const struct bpf_link_update_opts *opts)
|
const struct bpf_link_update_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, link_update);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
if (OPTS_GET(opts, old_prog_fd, 0) && OPTS_GET(opts, old_map_fd, 0))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_sz);
|
||||||
attr.link_update.link_fd = link_fd;
|
attr.link_update.link_fd = link_fd;
|
||||||
attr.link_update.new_prog_fd = new_prog_fd;
|
attr.link_update.new_prog_fd = new_prog_fd;
|
||||||
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
||||||
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
if (OPTS_GET(opts, old_prog_fd, 0))
|
||||||
|
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||||
|
else if (OPTS_GET(opts, old_map_fd, 0))
|
||||||
|
attr.link_update.old_map_fd = OPTS_GET(opts, old_map_fd, 0);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_LINK_UPDATE, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_iter_create(int link_fd)
|
int bpf_iter_create(int link_fd)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, iter_create);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.iter_create.link_fd = link_fd;
|
attr.iter_create.link_fd = link_fd;
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_ITER_CREATE, &attr, sizeof(attr));
|
fd = sys_bpf_fd(BPF_ITER_CREATE, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,13 +826,14 @@ int bpf_prog_query_opts(int target_fd,
|
|||||||
enum bpf_attach_type type,
|
enum bpf_attach_type type,
|
||||||
struct bpf_prog_query_opts *opts)
|
struct bpf_prog_query_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, query);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_prog_query_opts))
|
if (!OPTS_VALID(opts, bpf_prog_query_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
|
||||||
attr.query.target_fd = target_fd;
|
attr.query.target_fd = target_fd;
|
||||||
attr.query.attach_type = type;
|
attr.query.attach_type = type;
|
||||||
@@ -814,7 +842,7 @@ int bpf_prog_query_opts(int target_fd,
|
|||||||
attr.query.prog_ids = ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
|
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));
|
attr.query.prog_attach_flags = ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_QUERY, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_QUERY, &attr, attr_sz);
|
||||||
|
|
||||||
OPTS_SET(opts, attach_flags, attr.query.attach_flags);
|
OPTS_SET(opts, attach_flags, attr.query.attach_flags);
|
||||||
OPTS_SET(opts, prog_cnt, attr.query.prog_cnt);
|
OPTS_SET(opts, prog_cnt, attr.query.prog_cnt);
|
||||||
@@ -843,13 +871,14 @@ int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
|
|||||||
|
|
||||||
int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, test);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_test_run_opts))
|
if (!OPTS_VALID(opts, bpf_test_run_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.test.prog_fd = prog_fd;
|
attr.test.prog_fd = prog_fd;
|
||||||
attr.test.batch_size = OPTS_GET(opts, batch_size, 0);
|
attr.test.batch_size = OPTS_GET(opts, batch_size, 0);
|
||||||
attr.test.cpu = OPTS_GET(opts, cpu, 0);
|
attr.test.cpu = OPTS_GET(opts, cpu, 0);
|
||||||
@@ -865,7 +894,7 @@ int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
|||||||
attr.test.data_in = ptr_to_u64(OPTS_GET(opts, data_in, NULL));
|
attr.test.data_in = ptr_to_u64(OPTS_GET(opts, data_in, NULL));
|
||||||
attr.test.data_out = ptr_to_u64(OPTS_GET(opts, data_out, NULL));
|
attr.test.data_out = ptr_to_u64(OPTS_GET(opts, data_out, NULL));
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, attr_sz);
|
||||||
|
|
||||||
OPTS_SET(opts, data_size_out, attr.test.data_size_out);
|
OPTS_SET(opts, data_size_out, attr.test.data_size_out);
|
||||||
OPTS_SET(opts, ctx_size_out, attr.test.ctx_size_out);
|
OPTS_SET(opts, ctx_size_out, attr.test.ctx_size_out);
|
||||||
@@ -877,13 +906,14 @@ int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
|||||||
|
|
||||||
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.start_id = start_id;
|
attr.start_id = start_id;
|
||||||
|
|
||||||
err = sys_bpf(cmd, &attr, sizeof(attr));
|
err = sys_bpf(cmd, &attr, attr_sz);
|
||||||
if (!err)
|
if (!err)
|
||||||
*next_id = attr.next_id;
|
*next_id = attr.next_id;
|
||||||
|
|
||||||
@@ -910,88 +940,152 @@ int bpf_link_get_next_id(__u32 start_id, __u32 *next_id)
|
|||||||
return bpf_obj_get_next_id(start_id, next_id, BPF_LINK_GET_NEXT_ID);
|
return bpf_obj_get_next_id(start_id, next_id, BPF_LINK_GET_NEXT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_fd_by_id(__u32 id)
|
int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||||
attr.prog_id = id;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.prog_id = id;
|
||||||
|
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||||
|
|
||||||
|
fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, attr_sz);
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_prog_get_fd_by_id(__u32 id)
|
||||||
|
{
|
||||||
|
return bpf_prog_get_fd_by_id_opts(id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||||
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.map_id = id;
|
||||||
|
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||||
|
|
||||||
|
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_get_fd_by_id(__u32 id)
|
int bpf_map_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
|
return bpf_map_get_fd_by_id_opts(id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||||
attr.map_id = id;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.btf_id = id;
|
||||||
|
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||||
|
|
||||||
|
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_btf_get_fd_by_id(__u32 id)
|
int bpf_btf_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
|
return bpf_btf_get_fd_by_id_opts(id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||||
attr.btf_id = id;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.link_id = id;
|
||||||
|
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||||
|
|
||||||
|
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_get_fd_by_id(__u32 id)
|
int bpf_link_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
return bpf_link_get_fd_by_id_opts(id, NULL);
|
||||||
int fd;
|
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
|
||||||
attr.link_id = id;
|
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, sizeof(attr));
|
|
||||||
return libbpf_err_errno(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, info);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.info.bpf_fd = bpf_fd;
|
attr.info.bpf_fd = bpf_fd;
|
||||||
attr.info.info_len = *info_len;
|
attr.info.info_len = *info_len;
|
||||||
attr.info.info = ptr_to_u64(info);
|
attr.info.info = ptr_to_u64(info);
|
||||||
|
|
||||||
err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
|
err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, attr_sz);
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
*info_len = attr.info.info_len;
|
*info_len = attr.info.info_len;
|
||||||
|
|
||||||
return libbpf_err_errno(err);
|
return libbpf_err_errno(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, __u32 *info_len)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_info_by_fd(prog_fd, info, info_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_get_info_by_fd(int map_fd, struct bpf_map_info *info, __u32 *info_len)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_info_by_fd(map_fd, info, info_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u32 *info_len)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_info_by_fd(btf_fd, info, info_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_link_get_info_by_fd(int link_fd, struct bpf_link_info *info, __u32 *info_len)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_info_by_fd(link_fd, info, info_len);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
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;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.raw_tracepoint.name = ptr_to_u64(name);
|
attr.raw_tracepoint.name = ptr_to_u64(name);
|
||||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
|
fd = sys_bpf_fd(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_btf_load(const void *btf_data, size_t btf_size, const struct bpf_btf_load_opts *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_log_level);
|
const size_t attr_sz = offsetofend(union bpf_attr, btf_log_true_size);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
char *log_buf;
|
char *log_buf;
|
||||||
size_t log_size;
|
size_t log_size;
|
||||||
@@ -1034,6 +1128,8 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, const struct bpf_btf_loa
|
|||||||
attr.btf_log_level = 1;
|
attr.btf_log_level = 1;
|
||||||
fd = sys_bpf_fd(BPF_BTF_LOAD, &attr, attr_sz);
|
fd = sys_bpf_fd(BPF_BTF_LOAD, &attr, attr_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OPTS_SET(opts, log_true_size, attr.btf_log_true_size);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,16 +1137,18 @@ int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
|
|||||||
__u32 *prog_id, __u32 *fd_type, __u64 *probe_offset,
|
__u32 *prog_id, __u32 *fd_type, __u64 *probe_offset,
|
||||||
__u64 *probe_addr)
|
__u64 *probe_addr)
|
||||||
{
|
{
|
||||||
union bpf_attr attr = {};
|
const size_t attr_sz = offsetofend(union bpf_attr, task_fd_query);
|
||||||
|
union bpf_attr attr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_sz);
|
||||||
attr.task_fd_query.pid = pid;
|
attr.task_fd_query.pid = pid;
|
||||||
attr.task_fd_query.fd = fd;
|
attr.task_fd_query.fd = fd;
|
||||||
attr.task_fd_query.flags = flags;
|
attr.task_fd_query.flags = flags;
|
||||||
attr.task_fd_query.buf = ptr_to_u64(buf);
|
attr.task_fd_query.buf = ptr_to_u64(buf);
|
||||||
attr.task_fd_query.buf_len = *buf_len;
|
attr.task_fd_query.buf_len = *buf_len;
|
||||||
|
|
||||||
err = sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr));
|
err = sys_bpf(BPF_TASK_FD_QUERY, &attr, attr_sz);
|
||||||
|
|
||||||
*buf_len = attr.task_fd_query.buf_len;
|
*buf_len = attr.task_fd_query.buf_len;
|
||||||
*prog_id = attr.task_fd_query.prog_id;
|
*prog_id = attr.task_fd_query.prog_id;
|
||||||
@@ -1063,30 +1161,32 @@ int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
|
|||||||
|
|
||||||
int bpf_enable_stats(enum bpf_stats_type type)
|
int bpf_enable_stats(enum bpf_stats_type type)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, enable_stats);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.enable_stats.type = type;
|
attr.enable_stats.type = type;
|
||||||
|
|
||||||
fd = sys_bpf_fd(BPF_ENABLE_STATS, &attr, sizeof(attr));
|
fd = sys_bpf_fd(BPF_ENABLE_STATS, &attr, attr_sz);
|
||||||
return libbpf_err_errno(fd);
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_bind_map(int prog_fd, int map_fd,
|
int bpf_prog_bind_map(int prog_fd, int map_fd,
|
||||||
const struct bpf_prog_bind_opts *opts)
|
const struct bpf_prog_bind_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, prog_bind_map);
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_prog_bind_opts))
|
if (!OPTS_VALID(opts, bpf_prog_bind_opts))
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, attr_sz);
|
||||||
attr.prog_bind_map.prog_fd = prog_fd;
|
attr.prog_bind_map.prog_fd = prog_fd;
|
||||||
attr.prog_bind_map.map_fd = map_fd;
|
attr.prog_bind_map.map_fd = map_fd;
|
||||||
attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0);
|
attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, attr_sz);
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|||||||
129
src/bpf.h
@@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common eBPF ELF operations.
|
* Common BPF ELF operations.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
|
* Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
|
||||||
* Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
|
* Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
|
||||||
@@ -96,13 +96,20 @@ struct bpf_prog_load_opts {
|
|||||||
__u32 log_level;
|
__u32 log_level;
|
||||||
__u32 log_size;
|
__u32 log_size;
|
||||||
char *log_buf;
|
char *log_buf;
|
||||||
|
/* output: actual total log contents size (including termintaing zero).
|
||||||
|
* It could be both larger than original log_size (if log was
|
||||||
|
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||||
|
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||||
|
*/
|
||||||
|
__u32 log_true_size;
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_prog_load_opts__last_field log_buf
|
#define bpf_prog_load_opts__last_field log_true_size
|
||||||
|
|
||||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||||
const char *prog_name, const char *license,
|
const char *prog_name, const char *license,
|
||||||
const struct bpf_insn *insns, size_t insn_cnt,
|
const struct bpf_insn *insns, size_t insn_cnt,
|
||||||
const struct bpf_prog_load_opts *opts);
|
struct bpf_prog_load_opts *opts);
|
||||||
|
|
||||||
/* Flags to direct loading requirements */
|
/* Flags to direct loading requirements */
|
||||||
#define MAPS_RELAX_COMPAT 0x01
|
#define MAPS_RELAX_COMPAT 0x01
|
||||||
@@ -117,11 +124,18 @@ struct bpf_btf_load_opts {
|
|||||||
char *log_buf;
|
char *log_buf;
|
||||||
__u32 log_level;
|
__u32 log_level;
|
||||||
__u32 log_size;
|
__u32 log_size;
|
||||||
|
/* output: actual total log contents size (including termintaing zero).
|
||||||
|
* It could be both larger than original log_size (if log was
|
||||||
|
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||||
|
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||||
|
*/
|
||||||
|
__u32 log_true_size;
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_btf_load_opts__last_field log_size
|
#define bpf_btf_load_opts__last_field log_true_size
|
||||||
|
|
||||||
LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size,
|
LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size,
|
||||||
const struct bpf_btf_load_opts *opts);
|
struct bpf_btf_load_opts *opts);
|
||||||
|
|
||||||
LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
|
LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||||
__u64 flags);
|
__u64 flags);
|
||||||
@@ -270,8 +284,19 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values
|
|||||||
__u32 *count,
|
__u32 *count,
|
||||||
const struct bpf_map_batch_opts *opts);
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_obj_get_opts {
|
||||||
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
|
||||||
|
__u32 file_flags;
|
||||||
|
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_obj_get_opts__last_field file_flags
|
||||||
|
|
||||||
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
||||||
LIBBPF_API int bpf_obj_get(const char *pathname);
|
LIBBPF_API int bpf_obj_get(const char *pathname);
|
||||||
|
LIBBPF_API int bpf_obj_get_opts(const char *pathname,
|
||||||
|
const struct bpf_obj_get_opts *opts);
|
||||||
|
|
||||||
struct bpf_prog_attach_opts {
|
struct bpf_prog_attach_opts {
|
||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
@@ -325,8 +350,9 @@ struct bpf_link_update_opts {
|
|||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
__u32 flags; /* extra flags */
|
__u32 flags; /* extra flags */
|
||||||
__u32 old_prog_fd; /* expected old program FD */
|
__u32 old_prog_fd; /* expected old program FD */
|
||||||
|
__u32 old_map_fd; /* expected old map FD */
|
||||||
};
|
};
|
||||||
#define bpf_link_update_opts__last_field old_prog_fd
|
#define bpf_link_update_opts__last_field old_map_fd
|
||||||
|
|
||||||
LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
|
LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
|
||||||
const struct bpf_link_update_opts *opts);
|
const struct bpf_link_update_opts *opts);
|
||||||
@@ -354,12 +380,96 @@ LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
|||||||
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
|
LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
|
||||||
|
|
||||||
|
struct bpf_get_fd_by_id_opts {
|
||||||
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
__u32 open_flags; /* permissions requested for the operation on fd */
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_get_fd_by_id_opts__last_field open_flags
|
||||||
|
|
||||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||||
|
LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts);
|
||||||
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
||||||
|
LIBBPF_API int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts);
|
||||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||||
|
LIBBPF_API int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts);
|
||||||
LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
|
||||||
|
LIBBPF_API int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||||
|
const struct bpf_get_fd_by_id_opts *opts);
|
||||||
LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);
|
LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_prog_get_info_by_fd()** obtains information about the BPF
|
||||||
|
* 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*.
|
||||||
|
*
|
||||||
|
* @param prog_fd BPF program file descriptor
|
||||||
|
* @param info pointer to **struct bpf_prog_info** that will be populated with
|
||||||
|
* BPF program information
|
||||||
|
* @param info_len pointer to the size of *info*; on success updated with the
|
||||||
|
* number of bytes written to *info*
|
||||||
|
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||||
|
* the error code)
|
||||||
|
*/
|
||||||
|
LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, __u32 *info_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map_get_info_by_fd()** obtains information about the BPF
|
||||||
|
* 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*.
|
||||||
|
*
|
||||||
|
* @param map_fd BPF map file descriptor
|
||||||
|
* @param info pointer to **struct bpf_map_info** that will be populated with
|
||||||
|
* BPF map information
|
||||||
|
* @param info_len pointer to the size of *info*; on success updated with the
|
||||||
|
* number of bytes written to *info*
|
||||||
|
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||||
|
* the error code)
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* 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*.
|
||||||
|
*
|
||||||
|
* @param btf_fd BTF object file descriptor
|
||||||
|
* @param info pointer to **struct bpf_btf_info** that will be populated with
|
||||||
|
* BTF object information
|
||||||
|
* @param info_len pointer to the size of *info*; on success updated with the
|
||||||
|
* number of bytes written to *info*
|
||||||
|
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||||
|
* the error code)
|
||||||
|
*/
|
||||||
|
LIBBPF_API int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u32 *info_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_btf_get_info_by_fd()** obtains information about the BPF
|
||||||
|
* 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*.
|
||||||
|
*
|
||||||
|
* @param link_fd BPF link file descriptor
|
||||||
|
* @param info pointer to **struct bpf_link_info** that will be populated with
|
||||||
|
* BPF link information
|
||||||
|
* @param info_len pointer to the size of *info*; on success updated with the
|
||||||
|
* number of bytes written to *info*
|
||||||
|
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||||
|
* the error code)
|
||||||
|
*/
|
||||||
|
LIBBPF_API int bpf_link_get_info_by_fd(int link_fd, struct bpf_link_info *info, __u32 *info_len);
|
||||||
|
|
||||||
struct bpf_prog_query_opts {
|
struct bpf_prog_query_opts {
|
||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
__u32 query_flags;
|
__u32 query_flags;
|
||||||
@@ -382,8 +492,15 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
|
|||||||
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
|
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
|
||||||
__u64 *probe_offset, __u64 *probe_addr);
|
__u64 *probe_offset, __u64 *probe_addr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
/* forward-declaring enums in C++ isn't compatible with pure C enums, so
|
||||||
|
* instead define bpf_enable_stats() as accepting int as an input
|
||||||
|
*/
|
||||||
|
LIBBPF_API int bpf_enable_stats(int type);
|
||||||
|
#else
|
||||||
enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */
|
enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */
|
||||||
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);
|
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct bpf_prog_bind_opts {
|
struct bpf_prog_bind_opts {
|
||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ enum bpf_type_id_kind {
|
|||||||
enum bpf_type_info_kind {
|
enum bpf_type_info_kind {
|
||||||
BPF_TYPE_EXISTS = 0, /* type existence in target kernel */
|
BPF_TYPE_EXISTS = 0, /* type existence in target kernel */
|
||||||
BPF_TYPE_SIZE = 1, /* type size in target kernel */
|
BPF_TYPE_SIZE = 1, /* type size in target kernel */
|
||||||
|
BPF_TYPE_MATCHES = 2, /* type match in target kernel */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* second argument to __builtin_preserve_enum_value() built-in */
|
/* second argument to __builtin_preserve_enum_value() built-in */
|
||||||
@@ -183,6 +184,16 @@ enum bpf_enum_value_kind {
|
|||||||
#define bpf_core_type_exists(type) \
|
#define bpf_core_type_exists(type) \
|
||||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
|
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience macro to check that provided named type
|
||||||
|
* (struct/union/enum/typedef) "matches" that in a target kernel.
|
||||||
|
* Returns:
|
||||||
|
* 1, if the type matches in the target kernel's BTF;
|
||||||
|
* 0, if the type does not match any in the target kernel
|
||||||
|
*/
|
||||||
|
#define bpf_core_type_matches(type) \
|
||||||
|
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convenience macro to get the byte size of a provided named type
|
* Convenience macro to get the byte size of a provided named type
|
||||||
* (struct/union/enum/typedef) in a target kernel.
|
* (struct/union/enum/typedef) in a target kernel.
|
||||||
@@ -353,7 +364,7 @@ enum bpf_enum_value_kind {
|
|||||||
|
|
||||||
/* Non-CO-RE variant of BPF_CORE_READ_INTO() */
|
/* Non-CO-RE variant of BPF_CORE_READ_INTO() */
|
||||||
#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \
|
#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \
|
||||||
___core_read(bpf_probe_read, bpf_probe_read, \
|
___core_read(bpf_probe_read_kernel, bpf_probe_read_kernel, \
|
||||||
dst, (src), a, ##__VA_ARGS__) \
|
dst, (src), a, ##__VA_ARGS__) \
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -389,7 +400,7 @@ enum bpf_enum_value_kind {
|
|||||||
|
|
||||||
/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */
|
/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */
|
||||||
#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \
|
#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \
|
||||||
___core_read(bpf_probe_read_str, bpf_probe_read, \
|
___core_read(bpf_probe_read_kernel_str, bpf_probe_read_kernel, \
|
||||||
dst, (src), a, ##__VA_ARGS__) \
|
dst, (src), a, ##__VA_ARGS__) \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ struct ksym_relo_desc {
|
|||||||
int insn_idx;
|
int insn_idx;
|
||||||
bool is_weak;
|
bool is_weak;
|
||||||
bool is_typeless;
|
bool is_typeless;
|
||||||
|
bool is_ld64;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ksym_desc {
|
struct ksym_desc {
|
||||||
@@ -24,6 +25,7 @@ struct ksym_desc {
|
|||||||
bool typeless;
|
bool typeless;
|
||||||
};
|
};
|
||||||
int insn;
|
int insn;
|
||||||
|
bool is_ld64;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_gen {
|
struct bpf_gen {
|
||||||
@@ -65,7 +67,7 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *value, __u
|
|||||||
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
|
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
|
||||||
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
|
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
|
||||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||||
bool is_typeless, int kind, int insn_idx);
|
bool is_typeless, bool is_ld64, int kind, int insn_idx);
|
||||||
void bpf_gen__record_relo_core(struct bpf_gen *gen, const struct bpf_core_relo *core_relo);
|
void bpf_gen__record_relo_core(struct bpf_gen *gen, const struct bpf_core_relo *core_relo);
|
||||||
void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int key, int inner_map_idx);
|
void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int key, int inner_map_idx);
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ struct tcp_request_sock;
|
|||||||
struct udp6_sock;
|
struct udp6_sock;
|
||||||
struct unix_sock;
|
struct unix_sock;
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
|
struct cgroup;
|
||||||
struct __sk_buff;
|
struct __sk_buff;
|
||||||
struct sk_msg_md;
|
struct sk_msg_md;
|
||||||
struct xdp_md;
|
struct xdp_md;
|
||||||
@@ -117,17 +118,17 @@ static __u64 (*bpf_ktime_get_ns)(void) = (void *) 5;
|
|||||||
*
|
*
|
||||||
* This helper is a "printk()-like" facility for debugging. It
|
* This helper is a "printk()-like" facility for debugging. It
|
||||||
* prints a message defined by format *fmt* (of size *fmt_size*)
|
* prints a message defined by format *fmt* (of size *fmt_size*)
|
||||||
* to file *\/sys/kernel/debug/tracing/trace* from DebugFS, if
|
* to file *\/sys/kernel/tracing/trace* from TraceFS, if
|
||||||
* available. It can take up to three additional **u64**
|
* available. It can take up to three additional **u64**
|
||||||
* arguments (as an eBPF helpers, the total number of arguments is
|
* arguments (as an eBPF helpers, the total number of arguments is
|
||||||
* limited to five).
|
* limited to five).
|
||||||
*
|
*
|
||||||
* Each time the helper is called, it appends a line to the trace.
|
* Each time the helper is called, it appends a line to the trace.
|
||||||
* Lines are discarded while *\/sys/kernel/debug/tracing/trace* is
|
* Lines are discarded while *\/sys/kernel/tracing/trace* is
|
||||||
* open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this.
|
* open, use *\/sys/kernel/tracing/trace_pipe* to avoid this.
|
||||||
* The format of the trace is customizable, and the exact output
|
* The format of the trace is customizable, and the exact output
|
||||||
* one will get depends on the options set in
|
* one will get depends on the options set in
|
||||||
* *\/sys/kernel/debug/tracing/trace_options* (see also the
|
* *\/sys/kernel/tracing/trace_options* (see also the
|
||||||
* *README* file under the same directory). However, it usually
|
* *README* file under the same directory). However, it usually
|
||||||
* defaults to something like:
|
* defaults to something like:
|
||||||
*
|
*
|
||||||
@@ -536,6 +537,9 @@ static long (*bpf_skb_get_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_k
|
|||||||
* sending the packet. This flag was added for GRE
|
* sending the packet. This flag was added for GRE
|
||||||
* encapsulation, but might be used with other protocols
|
* encapsulation, but might be used with other protocols
|
||||||
* as well in the future.
|
* as well in the future.
|
||||||
|
* **BPF_F_NO_TUNNEL_KEY**
|
||||||
|
* Add a flag to tunnel metadata indicating that no tunnel
|
||||||
|
* key should be set in the resulting tunnel header.
|
||||||
*
|
*
|
||||||
* Here is a typical usage on the transmit path:
|
* Here is a typical usage on the transmit path:
|
||||||
*
|
*
|
||||||
@@ -1005,7 +1009,8 @@ static long (*bpf_skb_change_tail)(struct __sk_buff *skb, __u32 len, __u64 flags
|
|||||||
* Pull in non-linear data in case the *skb* is non-linear and not
|
* Pull in non-linear data in case the *skb* is non-linear and not
|
||||||
* all of *len* are part of the linear section. Make *len* bytes
|
* all of *len* are part of the linear section. Make *len* bytes
|
||||||
* from *skb* readable and writable. If a zero value is passed for
|
* from *skb* readable and writable. If a zero value is passed for
|
||||||
* *len*, then the whole length of the *skb* is pulled.
|
* *len*, then all bytes in the linear part of *skb* will be made
|
||||||
|
* readable and writable.
|
||||||
*
|
*
|
||||||
* This helper is only needed for reading and writing with direct
|
* This helper is only needed for reading and writing with direct
|
||||||
* packet access.
|
* packet access.
|
||||||
@@ -1208,14 +1213,19 @@ static long (*bpf_set_hash)(struct __sk_buff *skb, __u32 hash) = (void *) 48;
|
|||||||
* * **SOL_SOCKET**, which supports the following *optname*\ s:
|
* * **SOL_SOCKET**, which supports the following *optname*\ s:
|
||||||
* **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**,
|
* **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**,
|
||||||
* **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**,
|
* **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**,
|
||||||
* **SO_BINDTODEVICE**, **SO_KEEPALIVE**.
|
* **SO_BINDTODEVICE**, **SO_KEEPALIVE**, **SO_REUSEADDR**,
|
||||||
|
* **SO_REUSEPORT**, **SO_BINDTOIFINDEX**, **SO_TXREHASH**.
|
||||||
* * **IPPROTO_TCP**, which supports the following *optname*\ s:
|
* * **IPPROTO_TCP**, which supports the following *optname*\ s:
|
||||||
* **TCP_CONGESTION**, **TCP_BPF_IW**,
|
* **TCP_CONGESTION**, **TCP_BPF_IW**,
|
||||||
* **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,
|
* **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,
|
||||||
* **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,
|
* **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,
|
||||||
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**.
|
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
|
||||||
|
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
|
||||||
|
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
|
||||||
|
* **TCP_BPF_RTO_MIN**.
|
||||||
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
||||||
* * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.
|
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
|
||||||
|
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
@@ -1238,10 +1248,12 @@ static long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *op
|
|||||||
* There are two supported modes at this time:
|
* There are two supported modes at this time:
|
||||||
*
|
*
|
||||||
* * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer
|
* * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer
|
||||||
* (room space is added or removed below the layer 2 header).
|
* (room space is added or removed between the layer 2 and
|
||||||
|
* layer 3 headers).
|
||||||
*
|
*
|
||||||
* * **BPF_ADJ_ROOM_NET**: Adjust room at the network layer
|
* * **BPF_ADJ_ROOM_NET**: Adjust room at the network layer
|
||||||
* (room space is added or removed below the layer 3 header).
|
* (room space is added or removed between the layer 3 and
|
||||||
|
* layer 4 headers).
|
||||||
*
|
*
|
||||||
* The following flags are supported at this time:
|
* The following flags are supported at this time:
|
||||||
*
|
*
|
||||||
@@ -1265,6 +1277,11 @@ static long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *op
|
|||||||
* Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the
|
* Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the
|
||||||
* L2 type as Ethernet.
|
* L2 type as Ethernet.
|
||||||
*
|
*
|
||||||
|
* * **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**,
|
||||||
|
* **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**:
|
||||||
|
* Indicate the new IP header version after decapsulating the outer
|
||||||
|
* IP header. Used when the inner and outer IP versions are different.
|
||||||
|
*
|
||||||
* A call to this helper is susceptible to change the underlying
|
* A call to this helper is susceptible to change the underlying
|
||||||
* packet buffer. Therefore, at load time, all checks on pointers
|
* packet buffer. Therefore, at load time, all checks on pointers
|
||||||
* previously done by the verifier are invalidated and must be
|
* previously done by the verifier are invalidated and must be
|
||||||
@@ -1303,7 +1320,7 @@ static long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32
|
|||||||
* **XDP_REDIRECT** on success, or the value of the two lower bits
|
* **XDP_REDIRECT** on success, or the value of the two lower bits
|
||||||
* of the *flags* argument on error.
|
* of the *flags* argument on error.
|
||||||
*/
|
*/
|
||||||
static long (*bpf_redirect_map)(void *map, __u32 key, __u64 flags) = (void *) 51;
|
static long (*bpf_redirect_map)(void *map, __u64 key, __u64 flags) = (void *) 51;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_sk_redirect_map
|
* bpf_sk_redirect_map
|
||||||
@@ -1433,7 +1450,7 @@ static long (*bpf_perf_event_read_value)(void *map, __u64 flags, struct bpf_perf
|
|||||||
/*
|
/*
|
||||||
* bpf_perf_prog_read_value
|
* bpf_perf_prog_read_value
|
||||||
*
|
*
|
||||||
* For en eBPF program attached to a perf event, retrieve the
|
* For an eBPF program attached to a perf event, retrieve the
|
||||||
* value of the event counter associated to *ctx* and store it in
|
* value of the event counter associated to *ctx* and store it in
|
||||||
* the structure pointed by *buf* and of size *buf_size*. Enabled
|
* the structure pointed by *buf* and of size *buf_size*. Enabled
|
||||||
* and running times are also stored in the structure (see
|
* and running times are also stored in the structure (see
|
||||||
@@ -1462,12 +1479,10 @@ static long (*bpf_perf_prog_read_value)(struct bpf_perf_event_data *ctx, struct
|
|||||||
* and **BPF_CGROUP_INET6_CONNECT**.
|
* and **BPF_CGROUP_INET6_CONNECT**.
|
||||||
*
|
*
|
||||||
* This helper actually implements a subset of **getsockopt()**.
|
* This helper actually implements a subset of **getsockopt()**.
|
||||||
* It supports the following *level*\ s:
|
* It supports the same set of *optname*\ s that is supported by
|
||||||
*
|
* the **bpf_setsockopt**\ () helper. The exceptions are
|
||||||
* * **IPPROTO_TCP**, which supports *optname*
|
* **TCP_BPF_*** is **bpf_setsockopt**\ () only and
|
||||||
* **TCP_CONGESTION**.
|
* **TCP_SAVED_SYN** is **bpf_getsockopt**\ () only.
|
||||||
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
|
||||||
* * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.
|
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
@@ -1741,8 +1756,18 @@ static long (*bpf_skb_get_xfrm_state)(struct __sk_buff *skb, __u32 index, struct
|
|||||||
* **BPF_F_USER_STACK**
|
* **BPF_F_USER_STACK**
|
||||||
* Collect a user space stack instead of a kernel stack.
|
* Collect a user space stack instead of a kernel stack.
|
||||||
* **BPF_F_USER_BUILD_ID**
|
* **BPF_F_USER_BUILD_ID**
|
||||||
* Collect buildid+offset instead of ips for user stack,
|
* Collect (build_id, file_offset) instead of ips for user
|
||||||
* only valid if **BPF_F_USER_STACK** is also specified.
|
* stack, only valid if **BPF_F_USER_STACK** is also
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* *file_offset* is an offset relative to the beginning
|
||||||
|
* of the executable or shared object file backing the vma
|
||||||
|
* which the *ip* falls in. It is *not* an offset relative
|
||||||
|
* to that object's base address. Accordingly, it must be
|
||||||
|
* adjusted by adding (sh_addr - sh_offset), where
|
||||||
|
* sh_{addr,offset} correspond to the executable section
|
||||||
|
* containing *file_offset* in the object, for comparisons
|
||||||
|
* to symbols' st_value to be valid.
|
||||||
*
|
*
|
||||||
* **bpf_get_stack**\ () can collect up to
|
* **bpf_get_stack**\ () can collect up to
|
||||||
* **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
|
* **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject
|
||||||
@@ -1810,6 +1835,11 @@ static long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *
|
|||||||
* **BPF_FIB_LOOKUP_OUTPUT**
|
* **BPF_FIB_LOOKUP_OUTPUT**
|
||||||
* Perform lookup from an egress perspective (default is
|
* Perform lookup from an egress perspective (default is
|
||||||
* ingress).
|
* ingress).
|
||||||
|
* **BPF_FIB_LOOKUP_SKIP_NEIGH**
|
||||||
|
* Skip the neighbour table lookup. *params*->dmac
|
||||||
|
* and *params*->smac will not be set as output. A common
|
||||||
|
* use case is to call **bpf_redirect_neigh**\ () after
|
||||||
|
* doing **bpf_fib_lookup**\ ().
|
||||||
*
|
*
|
||||||
* *ctx* is either **struct xdp_md** for XDP programs or
|
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||||
* **struct sk_buff** tc cls_act programs.
|
* **struct sk_buff** tc cls_act programs.
|
||||||
@@ -3413,7 +3443,7 @@ static long (*bpf_load_hdr_opt)(struct bpf_sock_ops *skops, void *searchby_res,
|
|||||||
*
|
*
|
||||||
* **-EEXIST** if the option already exists.
|
* **-EEXIST** if the option already exists.
|
||||||
*
|
*
|
||||||
* **-EFAULT** on failrue to parse the existing header options.
|
* **-EFAULT** on failure to parse the existing header options.
|
||||||
*
|
*
|
||||||
* **-EPERM** if the helper cannot be used under the current
|
* **-EPERM** if the helper cannot be used under the current
|
||||||
* *skops*\ **->op**.
|
* *skops*\ **->op**.
|
||||||
@@ -3673,7 +3703,7 @@ static long (*bpf_redirect_peer)(__u32 ifindex, __u64 flags) = (void *) 155;
|
|||||||
* a *map* with *task* as the **key**. From this
|
* a *map* with *task* as the **key**. From this
|
||||||
* perspective, the usage is not much different from
|
* perspective, the usage is not much different from
|
||||||
* **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this
|
* **bpf_map_lookup_elem**\ (*map*, **&**\ *task*) except this
|
||||||
* helper enforces the key must be an task_struct and the map must also
|
* helper enforces the key must be a task_struct and the map must also
|
||||||
* be a **BPF_MAP_TYPE_TASK_STORAGE**.
|
* be a **BPF_MAP_TYPE_TASK_STORAGE**.
|
||||||
*
|
*
|
||||||
* Underneath, the value is stored locally at *task* instead of
|
* Underneath, the value is stored locally at *task* instead of
|
||||||
@@ -3751,7 +3781,7 @@ static __u64 (*bpf_ktime_get_coarse_ns)(void) = (void *) 160;
|
|||||||
/*
|
/*
|
||||||
* bpf_ima_inode_hash
|
* bpf_ima_inode_hash
|
||||||
*
|
*
|
||||||
* Returns the stored IMA hash of the *inode* (if it's avaialable).
|
* Returns the stored IMA hash of the *inode* (if it's available).
|
||||||
* If the hash is larger than *size*, then only *size*
|
* If the hash is larger than *size*, then only *size*
|
||||||
* bytes will be copied to *dst*
|
* bytes will be copied to *dst*
|
||||||
*
|
*
|
||||||
@@ -3783,12 +3813,12 @@ static struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162;
|
|||||||
*
|
*
|
||||||
* The argument *len_diff* can be used for querying with a planned
|
* The argument *len_diff* can be used for querying with a planned
|
||||||
* size change. This allows to check MTU prior to changing packet
|
* size change. This allows to check MTU prior to changing packet
|
||||||
* ctx. Providing an *len_diff* adjustment that is larger than the
|
* ctx. Providing a *len_diff* adjustment that is larger than the
|
||||||
* actual packet size (resulting in negative packet size) will in
|
* actual packet size (resulting in negative packet size) will in
|
||||||
* principle not exceed the MTU, why it is not considered a
|
* principle not exceed the MTU, which is why it is not considered
|
||||||
* failure. Other BPF-helpers are needed for performing the
|
* a failure. Other BPF helpers are needed for performing the
|
||||||
* planned size change, why the responsability for catch a negative
|
* planned size change; therefore the responsibility for catching
|
||||||
* packet size belong in those helpers.
|
* a negative packet size belongs in those helpers.
|
||||||
*
|
*
|
||||||
* Specifying *ifindex* zero means the MTU check is performed
|
* Specifying *ifindex* zero means the MTU check is performed
|
||||||
* against the current net device. This is practical if this isn't
|
* against the current net device. This is practical if this isn't
|
||||||
@@ -3998,6 +4028,12 @@ static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn
|
|||||||
* different maps if key/value layout matches across maps.
|
* different maps if key/value layout matches across maps.
|
||||||
* Every bpf_timer_set_callback() can have different callback_fn.
|
* Every bpf_timer_set_callback() can have different callback_fn.
|
||||||
*
|
*
|
||||||
|
* *flags* can be one of:
|
||||||
|
*
|
||||||
|
* **BPF_F_TIMER_ABS**
|
||||||
|
* Start the timer in absolute expire value instead of the
|
||||||
|
* default relative one.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success.
|
* 0 on success.
|
||||||
@@ -4027,6 +4063,7 @@ static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172;
|
|||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* Address of the traced function.
|
* Address of the traced function.
|
||||||
|
* 0 for kprobes placed within the function (not at the entry).
|
||||||
*/
|
*/
|
||||||
static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173;
|
static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173;
|
||||||
|
|
||||||
@@ -4195,13 +4232,13 @@ static long (*bpf_strncmp)(const char *s1, __u32 s1_sz, const char *s2) = (void
|
|||||||
/*
|
/*
|
||||||
* bpf_get_func_arg
|
* bpf_get_func_arg
|
||||||
*
|
*
|
||||||
* Get **n**-th argument (zero based) of the traced function (for tracing programs)
|
* Get **n**-th argument register (zero based) of the traced function (for tracing programs)
|
||||||
* returned in **value**.
|
* returned in **value**.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success.
|
* 0 on success.
|
||||||
* **-EINVAL** if n >= arguments count of traced function.
|
* **-EINVAL** if n >= argument register count of traced function.
|
||||||
*/
|
*/
|
||||||
static long (*bpf_get_func_arg)(void *ctx, __u32 n, __u64 *value) = (void *) 183;
|
static long (*bpf_get_func_arg)(void *ctx, __u32 n, __u64 *value) = (void *) 183;
|
||||||
|
|
||||||
@@ -4221,32 +4258,45 @@ static long (*bpf_get_func_ret)(void *ctx, __u64 *value) = (void *) 184;
|
|||||||
/*
|
/*
|
||||||
* bpf_get_func_arg_cnt
|
* bpf_get_func_arg_cnt
|
||||||
*
|
*
|
||||||
* Get number of arguments of the traced function (for tracing programs).
|
* Get number of registers of the traced function (for tracing programs) where
|
||||||
|
* function arguments are stored in these registers.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* The number of arguments of the traced function.
|
* The number of argument registers of the traced function.
|
||||||
*/
|
*/
|
||||||
static long (*bpf_get_func_arg_cnt)(void *ctx) = (void *) 185;
|
static long (*bpf_get_func_arg_cnt)(void *ctx) = (void *) 185;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_get_retval
|
* bpf_get_retval
|
||||||
*
|
*
|
||||||
* Get the syscall's return value that will be returned to userspace.
|
* Get the BPF program's return value that will be returned to the upper layers.
|
||||||
*
|
*
|
||||||
* This helper is currently supported by cgroup programs only.
|
* This helper is currently supported by cgroup programs and only by the hooks
|
||||||
|
* where BPF program's return value is returned to the userspace via errno.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* The syscall's return value.
|
* The BPF program's return value.
|
||||||
*/
|
*/
|
||||||
static int (*bpf_get_retval)(void) = (void *) 186;
|
static int (*bpf_get_retval)(void) = (void *) 186;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_set_retval
|
* bpf_set_retval
|
||||||
*
|
*
|
||||||
* Set the syscall's return value that will be returned to userspace.
|
* Set the BPF program's return value that will be returned to the upper layers.
|
||||||
|
*
|
||||||
|
* This helper is currently supported by cgroup programs and only by the hooks
|
||||||
|
* where BPF program's return value is returned to the userspace via errno.
|
||||||
|
*
|
||||||
|
* Note that there is the following corner case where the program exports an error
|
||||||
|
* via bpf_set_retval but signals success via 'return 1':
|
||||||
|
*
|
||||||
|
* bpf_set_retval(-EPERM);
|
||||||
|
* return 1;
|
||||||
|
*
|
||||||
|
* In this case, the BPF program's return value will use helper's -EPERM. This
|
||||||
|
* still holds true for cgroup/bind{4,6} which supports extra 'return 3' success case.
|
||||||
*
|
*
|
||||||
* This helper is currently supported by cgroup programs only.
|
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
@@ -4450,12 +4500,14 @@ static void (*bpf_ringbuf_discard_dynptr)(struct bpf_dynptr *ptr, __u64 flags) =
|
|||||||
*
|
*
|
||||||
* Read *len* bytes from *src* into *dst*, starting from *offset*
|
* Read *len* bytes from *src* into *dst*, starting from *offset*
|
||||||
* into *src*.
|
* into *src*.
|
||||||
|
* *flags* is currently unused.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
||||||
* of *src*'s data, -EINVAL if *src* is an invalid dynptr.
|
* of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
|
||||||
|
* *flags* is not 0.
|
||||||
*/
|
*/
|
||||||
static long (*bpf_dynptr_read)(void *dst, __u32 len, struct bpf_dynptr *src, __u32 offset) = (void *) 201;
|
static long (*bpf_dynptr_read)(void *dst, __u32 len, const struct bpf_dynptr *src, __u32 offset, __u64 flags) = (void *) 201;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_dynptr_write
|
* bpf_dynptr_write
|
||||||
@@ -4463,12 +4515,24 @@ static long (*bpf_dynptr_read)(void *dst, __u32 len, struct bpf_dynptr *src, __u
|
|||||||
* Write *len* bytes from *src* into *dst*, starting from *offset*
|
* Write *len* bytes from *src* into *dst*, starting from *offset*
|
||||||
* into *dst*.
|
* into *dst*.
|
||||||
*
|
*
|
||||||
|
* *flags* must be 0 except for skb-type dynptrs.
|
||||||
|
*
|
||||||
|
* For skb-type dynptrs:
|
||||||
|
* * All data slices of the dynptr are automatically
|
||||||
|
* invalidated after **bpf_dynptr_write**\ (). This is
|
||||||
|
* because writing may pull the skb and change the
|
||||||
|
* underlying packet buffer.
|
||||||
|
*
|
||||||
|
* * For *flags*, please see the flags accepted by
|
||||||
|
* **bpf_skb_store_bytes**\ ().
|
||||||
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
||||||
* of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
|
* of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
|
||||||
* is a read-only dynptr.
|
* is a read-only dynptr or if *flags* is not correct. For skb-type dynptrs,
|
||||||
|
* other errors correspond to errors returned by **bpf_skb_store_bytes**\ ().
|
||||||
*/
|
*/
|
||||||
static long (*bpf_dynptr_write)(struct bpf_dynptr *dst, __u32 offset, void *src, __u32 len) = (void *) 202;
|
static long (*bpf_dynptr_write)(const struct bpf_dynptr *dst, __u32 offset, void *src, __u32 len, __u64 flags) = (void *) 202;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_dynptr_data
|
* bpf_dynptr_data
|
||||||
@@ -4478,12 +4542,15 @@ static long (*bpf_dynptr_write)(struct bpf_dynptr *dst, __u32 offset, void *src,
|
|||||||
* *len* must be a statically known value. The returned data slice
|
* *len* must be a statically known value. The returned data slice
|
||||||
* is invalidated whenever the dynptr is invalidated.
|
* is invalidated whenever the dynptr is invalidated.
|
||||||
*
|
*
|
||||||
|
* skb and xdp type dynptrs may not use bpf_dynptr_data. They should
|
||||||
|
* instead use bpf_dynptr_slice and bpf_dynptr_slice_rdwr.
|
||||||
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* Pointer to the underlying dynptr data, NULL if the dynptr is
|
* Pointer to the underlying dynptr data, NULL if the dynptr is
|
||||||
* read-only, if the dynptr is invalid, or if the offset and length
|
* read-only, if the dynptr is invalid, or if the offset and length
|
||||||
* is out of bounds.
|
* is out of bounds.
|
||||||
*/
|
*/
|
||||||
static void *(*bpf_dynptr_data)(struct bpf_dynptr *ptr, __u32 offset, __u32 len) = (void *) 203;
|
static void *(*bpf_dynptr_data)(const struct bpf_dynptr *ptr, __u32 offset, __u32 len) = (void *) 203;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_tcp_raw_gen_syncookie_ipv4
|
* bpf_tcp_raw_gen_syncookie_ipv4
|
||||||
@@ -4575,4 +4642,107 @@ static long (*bpf_tcp_raw_check_syncookie_ipv4)(struct iphdr *iph, struct tcphdr
|
|||||||
*/
|
*/
|
||||||
static long (*bpf_tcp_raw_check_syncookie_ipv6)(struct ipv6hdr *iph, struct tcphdr *th) = (void *) 207;
|
static long (*bpf_tcp_raw_check_syncookie_ipv6)(struct ipv6hdr *iph, struct tcphdr *th) = (void *) 207;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_ktime_get_tai_ns
|
||||||
|
*
|
||||||
|
* A nonsettable system-wide clock derived from wall-clock time but
|
||||||
|
* ignoring leap seconds. This clock does not experience
|
||||||
|
* discontinuities and backwards jumps caused by NTP inserting leap
|
||||||
|
* seconds as CLOCK_REALTIME does.
|
||||||
|
*
|
||||||
|
* See: **clock_gettime**\ (**CLOCK_TAI**)
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* Current *ktime*.
|
||||||
|
*/
|
||||||
|
static __u64 (*bpf_ktime_get_tai_ns)(void) = (void *) 208;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_user_ringbuf_drain
|
||||||
|
*
|
||||||
|
* Drain samples from the specified user ring buffer, and invoke
|
||||||
|
* the provided callback for each such sample:
|
||||||
|
*
|
||||||
|
* long (\*callback_fn)(const struct bpf_dynptr \*dynptr, void \*ctx);
|
||||||
|
*
|
||||||
|
* If **callback_fn** returns 0, the helper will continue to try
|
||||||
|
* and drain the next sample, up to a maximum of
|
||||||
|
* BPF_MAX_USER_RINGBUF_SAMPLES samples. If the return value is 1,
|
||||||
|
* the helper will skip the rest of the samples and return. Other
|
||||||
|
* return values are not used now, and will be rejected by the
|
||||||
|
* verifier.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* The number of drained samples if no error was encountered while
|
||||||
|
* draining samples, or 0 if no samples were present in the ring
|
||||||
|
* buffer. If a user-space producer was epoll-waiting on this map,
|
||||||
|
* and at least one sample was drained, they will receive an event
|
||||||
|
* notification notifying them of available space in the ring
|
||||||
|
* buffer. If the BPF_RB_NO_WAKEUP flag is passed to this
|
||||||
|
* function, no wakeup notification will be sent. If the
|
||||||
|
* BPF_RB_FORCE_WAKEUP flag is passed, a wakeup notification will
|
||||||
|
* be sent even if no sample was drained.
|
||||||
|
*
|
||||||
|
* On failure, the returned value is one of the following:
|
||||||
|
*
|
||||||
|
* **-EBUSY** if the ring buffer is contended, and another calling
|
||||||
|
* context was concurrently draining the ring buffer.
|
||||||
|
*
|
||||||
|
* **-EINVAL** if user-space is not properly tracking the ring
|
||||||
|
* buffer due to the producer position not being aligned to 8
|
||||||
|
* bytes, a sample not being aligned to 8 bytes, or the producer
|
||||||
|
* position not matching the advertised length of a sample.
|
||||||
|
*
|
||||||
|
* **-E2BIG** if user-space has tried to publish a sample which is
|
||||||
|
* larger than the size of the ring buffer, or which cannot fit
|
||||||
|
* within a struct bpf_dynptr.
|
||||||
|
*/
|
||||||
|
static long (*bpf_user_ringbuf_drain)(void *map, void *callback_fn, void *ctx, __u64 flags) = (void *) 209;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_cgrp_storage_get
|
||||||
|
*
|
||||||
|
* Get a bpf_local_storage from the *cgroup*.
|
||||||
|
*
|
||||||
|
* Logically, it could be thought of as getting the value from
|
||||||
|
* a *map* with *cgroup* as the **key**. From this
|
||||||
|
* perspective, the usage is not much different from
|
||||||
|
* **bpf_map_lookup_elem**\ (*map*, **&**\ *cgroup*) except this
|
||||||
|
* helper enforces the key must be a cgroup struct and the map must also
|
||||||
|
* be a **BPF_MAP_TYPE_CGRP_STORAGE**.
|
||||||
|
*
|
||||||
|
* In reality, the local-storage value is embedded directly inside of the
|
||||||
|
* *cgroup* object itself, rather than being located in the
|
||||||
|
* **BPF_MAP_TYPE_CGRP_STORAGE** map. When the local-storage value is
|
||||||
|
* queried for some *map* on a *cgroup* object, the kernel will perform an
|
||||||
|
* O(n) iteration over all of the live local-storage values for that
|
||||||
|
* *cgroup* object until the local-storage value for the *map* is found.
|
||||||
|
*
|
||||||
|
* An optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be
|
||||||
|
* used such that a new bpf_local_storage will be
|
||||||
|
* created if one does not exist. *value* can be used
|
||||||
|
* together with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify
|
||||||
|
* the initial value of a bpf_local_storage. If *value* is
|
||||||
|
* **NULL**, the new bpf_local_storage will be zero initialized.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* A bpf_local_storage pointer is returned on success.
|
||||||
|
*
|
||||||
|
* **NULL** if not found or there was an error in adding
|
||||||
|
* a new bpf_local_storage.
|
||||||
|
*/
|
||||||
|
static void *(*bpf_cgrp_storage_get)(void *map, struct cgroup *cgroup, void *value, __u64 flags) = (void *) 210;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_cgrp_storage_delete
|
||||||
|
*
|
||||||
|
* Delete a bpf_local_storage from a *cgroup*.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 on success.
|
||||||
|
*
|
||||||
|
* **-ENOENT** if the bpf_local_storage cannot be found.
|
||||||
|
*/
|
||||||
|
static long (*bpf_cgrp_storage_delete)(void *map, struct cgroup *cgroup) = (void *) 211;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,25 @@
|
|||||||
* To allow use of SEC() with externs (e.g., for extern .maps declarations),
|
* To allow use of SEC() with externs (e.g., for extern .maps declarations),
|
||||||
* make sure __attribute__((unused)) doesn't trigger compilation warning.
|
* make sure __attribute__((unused)) doesn't trigger compilation warning.
|
||||||
*/
|
*/
|
||||||
|
#if __GNUC__ && !__clang__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pragma macros are broken on GCC
|
||||||
|
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
|
||||||
|
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90400
|
||||||
|
*/
|
||||||
|
#define SEC(name) __attribute__((section(name), used))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#define SEC(name) \
|
#define SEC(name) \
|
||||||
_Pragma("GCC diagnostic push") \
|
_Pragma("GCC diagnostic push") \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
|
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
|
||||||
__attribute__((section(name), used)) \
|
__attribute__((section(name), used)) \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
|
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
|
||||||
#undef __always_inline
|
#undef __always_inline
|
||||||
#define __always_inline inline __attribute__((always_inline))
|
#define __always_inline inline __attribute__((always_inline))
|
||||||
@@ -96,7 +109,7 @@
|
|||||||
* This is a variable-specific variant of more global barrier().
|
* This is a variable-specific variant of more global barrier().
|
||||||
*/
|
*/
|
||||||
#ifndef barrier_var
|
#ifndef barrier_var
|
||||||
#define barrier_var(var) asm volatile("" : "=r"(var) : "0"(var))
|
#define barrier_var(var) asm volatile("" : "+r"(var))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -147,18 +160,6 @@ bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper structure used by eBPF C program
|
|
||||||
* to describe BPF map attributes to libbpf loader
|
|
||||||
*/
|
|
||||||
struct bpf_map_def {
|
|
||||||
unsigned int type;
|
|
||||||
unsigned int key_size;
|
|
||||||
unsigned int value_size;
|
|
||||||
unsigned int max_entries;
|
|
||||||
unsigned int map_flags;
|
|
||||||
} __attribute__((deprecated("use BTF-defined maps in .maps section")));
|
|
||||||
|
|
||||||
enum libbpf_pin_type {
|
enum libbpf_pin_type {
|
||||||
LIBBPF_PIN_NONE,
|
LIBBPF_PIN_NONE,
|
||||||
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
|
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
|
||||||
@@ -173,8 +174,13 @@ enum libbpf_tristate {
|
|||||||
|
|
||||||
#define __kconfig __attribute__((section(".kconfig")))
|
#define __kconfig __attribute__((section(".kconfig")))
|
||||||
#define __ksym __attribute__((section(".ksyms")))
|
#define __ksym __attribute__((section(".ksyms")))
|
||||||
|
#define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
|
||||||
#define __kptr __attribute__((btf_type_tag("kptr")))
|
#define __kptr __attribute__((btf_type_tag("kptr")))
|
||||||
#define __kptr_ref __attribute__((btf_type_tag("kptr_ref")))
|
|
||||||
|
#define bpf_ksym_exists(sym) ({ \
|
||||||
|
_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \
|
||||||
|
!!sym; \
|
||||||
|
})
|
||||||
|
|
||||||
#ifndef ___bpf_concat
|
#ifndef ___bpf_concat
|
||||||
#define ___bpf_concat(a, b) a ## b
|
#define ___bpf_concat(a, b) a ## b
|
||||||
@@ -285,4 +291,107 @@ enum libbpf_tristate {
|
|||||||
/* Helper macro to print out debug messages */
|
/* Helper macro to print out debug messages */
|
||||||
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
|
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
|
||||||
|
|
||||||
|
struct bpf_iter_num;
|
||||||
|
|
||||||
|
extern int bpf_iter_num_new(struct bpf_iter_num *it, int start, int end) __weak __ksym;
|
||||||
|
extern int *bpf_iter_num_next(struct bpf_iter_num *it) __weak __ksym;
|
||||||
|
extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
|
||||||
|
|
||||||
|
#ifndef bpf_for_each
|
||||||
|
/* bpf_for_each(iter_type, cur_elem, args...) provides generic construct for
|
||||||
|
* using BPF open-coded iterators without having to write mundane explicit
|
||||||
|
* low-level loop logic. Instead, it provides for()-like generic construct
|
||||||
|
* that can be used pretty naturally. E.g., for some hypothetical cgroup
|
||||||
|
* iterator, you'd write:
|
||||||
|
*
|
||||||
|
* struct cgroup *cg, *parent_cg = <...>;
|
||||||
|
*
|
||||||
|
* bpf_for_each(cgroup, cg, parent_cg, CG_ITER_CHILDREN) {
|
||||||
|
* bpf_printk("Child cgroup id = %d", cg->cgroup_id);
|
||||||
|
* if (cg->cgroup_id == 123)
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* I.e., it looks almost like high-level for each loop in other languages,
|
||||||
|
* supports continue/break, and is verifiable by BPF verifier.
|
||||||
|
*
|
||||||
|
* For iterating integers, the difference betwen bpf_for_each(num, i, N, M)
|
||||||
|
* and bpf_for(i, N, M) is in that bpf_for() provides additional proof to
|
||||||
|
* verifier that i is in [N, M) range, and in bpf_for_each() case i is `int
|
||||||
|
* *`, not just `int`. So for integers bpf_for() is more convenient.
|
||||||
|
*
|
||||||
|
* Note: this macro relies on C99 feature of allowing to declare variables
|
||||||
|
* inside for() loop, bound to for() loop lifetime. It also utilizes GCC
|
||||||
|
* extension: __attribute__((cleanup(<func>))), supported by both GCC and
|
||||||
|
* Clang.
|
||||||
|
*/
|
||||||
|
#define bpf_for_each(type, cur, args...) for ( \
|
||||||
|
/* initialize and define destructor */ \
|
||||||
|
struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */, \
|
||||||
|
cleanup(bpf_iter_##type##_destroy))), \
|
||||||
|
/* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */ \
|
||||||
|
*___p __attribute__((unused)) = ( \
|
||||||
|
bpf_iter_##type##_new(&___it, ##args), \
|
||||||
|
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||||
|
/* for bpf_iter_##type##_destroy() when used from cleanup() attribute */ \
|
||||||
|
(void)bpf_iter_##type##_destroy, (void *)0); \
|
||||||
|
/* iteration and termination check */ \
|
||||||
|
(((cur) = bpf_iter_##type##_next(&___it))); \
|
||||||
|
)
|
||||||
|
#endif /* bpf_for_each */
|
||||||
|
|
||||||
|
#ifndef bpf_for
|
||||||
|
/* bpf_for(i, start, end) implements a for()-like looping construct that sets
|
||||||
|
* provided integer variable *i* to values starting from *start* through,
|
||||||
|
* but not including, *end*. It also proves to BPF verifier that *i* belongs
|
||||||
|
* to range [start, end), so this can be used for accessing arrays without
|
||||||
|
* extra checks.
|
||||||
|
*
|
||||||
|
* Note: *start* and *end* are assumed to be expressions with no side effects
|
||||||
|
* and whose values do not change throughout bpf_for() loop execution. They do
|
||||||
|
* not have to be statically known or constant, though.
|
||||||
|
*
|
||||||
|
* Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
|
||||||
|
* loop bound variables and cleanup attribute, supported by GCC and Clang.
|
||||||
|
*/
|
||||||
|
#define bpf_for(i, start, end) for ( \
|
||||||
|
/* initialize and define destructor */ \
|
||||||
|
struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \
|
||||||
|
cleanup(bpf_iter_num_destroy))), \
|
||||||
|
/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \
|
||||||
|
*___p __attribute__((unused)) = ( \
|
||||||
|
bpf_iter_num_new(&___it, (start), (end)), \
|
||||||
|
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||||
|
/* for bpf_iter_num_destroy() when used from cleanup() attribute */ \
|
||||||
|
(void)bpf_iter_num_destroy, (void *)0); \
|
||||||
|
({ \
|
||||||
|
/* iteration step */ \
|
||||||
|
int *___t = bpf_iter_num_next(&___it); \
|
||||||
|
/* termination and bounds check */ \
|
||||||
|
(___t && ((i) = *___t, (i) >= (start) && (i) < (end))); \
|
||||||
|
}); \
|
||||||
|
)
|
||||||
|
#endif /* bpf_for */
|
||||||
|
|
||||||
|
#ifndef bpf_repeat
|
||||||
|
/* bpf_repeat(N) performs N iterations without exposing iteration number
|
||||||
|
*
|
||||||
|
* Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
|
||||||
|
* loop bound variables and cleanup attribute, supported by GCC and Clang.
|
||||||
|
*/
|
||||||
|
#define bpf_repeat(N) for ( \
|
||||||
|
/* initialize and define destructor */ \
|
||||||
|
struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \
|
||||||
|
cleanup(bpf_iter_num_destroy))), \
|
||||||
|
/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \
|
||||||
|
*___p __attribute__((unused)) = ( \
|
||||||
|
bpf_iter_num_new(&___it, 0, (N)), \
|
||||||
|
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||||
|
/* for bpf_iter_num_destroy() when used from cleanup() attribute */ \
|
||||||
|
(void)bpf_iter_num_destroy, (void *)0); \
|
||||||
|
bpf_iter_num_next(&___it); \
|
||||||
|
/* nothing here */ \
|
||||||
|
)
|
||||||
|
#endif /* bpf_repeat */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#ifndef __BPF_TRACING_H__
|
#ifndef __BPF_TRACING_H__
|
||||||
#define __BPF_TRACING_H__
|
#define __BPF_TRACING_H__
|
||||||
|
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
|
||||||
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
||||||
#if defined(__TARGET_ARCH_x86)
|
#if defined(__TARGET_ARCH_x86)
|
||||||
#define bpf_target_x86
|
#define bpf_target_x86
|
||||||
@@ -30,6 +32,9 @@
|
|||||||
#elif defined(__TARGET_ARCH_arc)
|
#elif defined(__TARGET_ARCH_arc)
|
||||||
#define bpf_target_arc
|
#define bpf_target_arc
|
||||||
#define bpf_target_defined
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_loongarch)
|
||||||
|
#define bpf_target_loongarch
|
||||||
|
#define bpf_target_defined
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Fall back to what the compiler says */
|
/* Fall back to what the compiler says */
|
||||||
@@ -60,6 +65,9 @@
|
|||||||
#elif defined(__arc__)
|
#elif defined(__arc__)
|
||||||
#define bpf_target_arc
|
#define bpf_target_arc
|
||||||
#define bpf_target_defined
|
#define bpf_target_defined
|
||||||
|
#elif defined(__loongarch__)
|
||||||
|
#define bpf_target_loongarch
|
||||||
|
#define bpf_target_defined
|
||||||
#endif /* no compiler target */
|
#endif /* no compiler target */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -70,6 +78,10 @@
|
|||||||
|
|
||||||
#if defined(bpf_target_x86)
|
#if defined(bpf_target_x86)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(__KERNEL__) || defined(__VMLINUX_H__)
|
#if defined(__KERNEL__) || defined(__VMLINUX_H__)
|
||||||
|
|
||||||
#define __PT_PARM1_REG di
|
#define __PT_PARM1_REG di
|
||||||
@@ -77,25 +89,40 @@
|
|||||||
#define __PT_PARM3_REG dx
|
#define __PT_PARM3_REG dx
|
||||||
#define __PT_PARM4_REG cx
|
#define __PT_PARM4_REG cx
|
||||||
#define __PT_PARM5_REG r8
|
#define __PT_PARM5_REG r8
|
||||||
|
#define __PT_PARM6_REG r9
|
||||||
|
/*
|
||||||
|
* Syscall uses r10 for PARM4. See arch/x86/entry/entry_64.S:entry_SYSCALL_64
|
||||||
|
* comments in Linux sources. And refer to syscall(2) manpage.
|
||||||
|
*/
|
||||||
|
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG r10
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
#define __PT_RET_REG sp
|
#define __PT_RET_REG sp
|
||||||
#define __PT_FP_REG bp
|
#define __PT_FP_REG bp
|
||||||
#define __PT_RC_REG ax
|
#define __PT_RC_REG ax
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG ip
|
#define __PT_IP_REG ip
|
||||||
/* syscall uses r10 for PARM4 */
|
|
||||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
|
||||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
|
||||||
|
/* i386 kernel is built with -mregparm=3 */
|
||||||
#define __PT_PARM1_REG eax
|
#define __PT_PARM1_REG eax
|
||||||
#define __PT_PARM2_REG edx
|
#define __PT_PARM2_REG edx
|
||||||
#define __PT_PARM3_REG ecx
|
#define __PT_PARM3_REG ecx
|
||||||
/* i386 kernel is built with -mregparm=3 */
|
/* i386 syscall ABI is very different, refer to syscall(2) manpage */
|
||||||
#define __PT_PARM4_REG __unsupported__
|
#define __PT_PARM1_SYSCALL_REG ebx
|
||||||
#define __PT_PARM5_REG __unsupported__
|
#define __PT_PARM2_SYSCALL_REG ecx
|
||||||
|
#define __PT_PARM3_SYSCALL_REG edx
|
||||||
|
#define __PT_PARM4_SYSCALL_REG esi
|
||||||
|
#define __PT_PARM5_SYSCALL_REG edi
|
||||||
|
#define __PT_PARM6_SYSCALL_REG ebp
|
||||||
|
|
||||||
#define __PT_RET_REG esp
|
#define __PT_RET_REG esp
|
||||||
#define __PT_FP_REG ebp
|
#define __PT_FP_REG ebp
|
||||||
#define __PT_RC_REG eax
|
#define __PT_RC_REG eax
|
||||||
@@ -109,14 +136,20 @@
|
|||||||
#define __PT_PARM3_REG rdx
|
#define __PT_PARM3_REG rdx
|
||||||
#define __PT_PARM4_REG rcx
|
#define __PT_PARM4_REG rcx
|
||||||
#define __PT_PARM5_REG r8
|
#define __PT_PARM5_REG r8
|
||||||
|
#define __PT_PARM6_REG r9
|
||||||
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG r10
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
#define __PT_RET_REG rsp
|
#define __PT_RET_REG rsp
|
||||||
#define __PT_FP_REG rbp
|
#define __PT_FP_REG rbp
|
||||||
#define __PT_RC_REG rax
|
#define __PT_RC_REG rax
|
||||||
#define __PT_SP_REG rsp
|
#define __PT_SP_REG rsp
|
||||||
#define __PT_IP_REG rip
|
#define __PT_IP_REG rip
|
||||||
/* syscall uses r10 for PARM4 */
|
|
||||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
|
||||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
|
||||||
|
|
||||||
#endif /* __i386__ */
|
#endif /* __i386__ */
|
||||||
|
|
||||||
@@ -124,6 +157,10 @@
|
|||||||
|
|
||||||
#elif defined(bpf_target_s390)
|
#elif defined(bpf_target_s390)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
struct pt_regs___s390 {
|
struct pt_regs___s390 {
|
||||||
unsigned long orig_gpr2;
|
unsigned long orig_gpr2;
|
||||||
};
|
};
|
||||||
@@ -135,21 +172,42 @@ struct pt_regs___s390 {
|
|||||||
#define __PT_PARM3_REG gprs[4]
|
#define __PT_PARM3_REG gprs[4]
|
||||||
#define __PT_PARM4_REG gprs[5]
|
#define __PT_PARM4_REG gprs[5]
|
||||||
#define __PT_PARM5_REG gprs[6]
|
#define __PT_PARM5_REG gprs[6]
|
||||||
#define __PT_RET_REG grps[14]
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG orig_gpr2
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG gprs[7]
|
||||||
|
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||||
|
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||||
|
BPF_CORE_READ((const struct pt_regs___s390 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||||
|
|
||||||
|
#define __PT_RET_REG gprs[14]
|
||||||
#define __PT_FP_REG gprs[11] /* Works only with CONFIG_FRAME_POINTER */
|
#define __PT_FP_REG gprs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||||
#define __PT_RC_REG gprs[2]
|
#define __PT_RC_REG gprs[2]
|
||||||
#define __PT_SP_REG gprs[15]
|
#define __PT_SP_REG gprs[15]
|
||||||
#define __PT_IP_REG psw.addr
|
#define __PT_IP_REG psw.addr
|
||||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
|
||||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___s390 *)(x), orig_gpr2)
|
|
||||||
|
|
||||||
#elif defined(bpf_target_arm)
|
#elif defined(bpf_target_arm)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers
|
||||||
|
*/
|
||||||
|
|
||||||
#define __PT_PARM1_REG uregs[0]
|
#define __PT_PARM1_REG uregs[0]
|
||||||
#define __PT_PARM2_REG uregs[1]
|
#define __PT_PARM2_REG uregs[1]
|
||||||
#define __PT_PARM3_REG uregs[2]
|
#define __PT_PARM3_REG uregs[2]
|
||||||
#define __PT_PARM4_REG uregs[3]
|
#define __PT_PARM4_REG uregs[3]
|
||||||
#define __PT_PARM5_REG uregs[4]
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG uregs[4]
|
||||||
|
#define __PT_PARM6_SYSCALL_REG uregs[5]
|
||||||
|
#define __PT_PARM7_SYSCALL_REG uregs[6]
|
||||||
|
|
||||||
#define __PT_RET_REG uregs[14]
|
#define __PT_RET_REG uregs[14]
|
||||||
#define __PT_FP_REG uregs[11] /* Works only with CONFIG_FRAME_POINTER */
|
#define __PT_FP_REG uregs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||||
#define __PT_RC_REG uregs[0]
|
#define __PT_RC_REG uregs[0]
|
||||||
@@ -158,6 +216,10 @@ struct pt_regs___s390 {
|
|||||||
|
|
||||||
#elif defined(bpf_target_arm64)
|
#elif defined(bpf_target_arm64)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers
|
||||||
|
*/
|
||||||
|
|
||||||
struct pt_regs___arm64 {
|
struct pt_regs___arm64 {
|
||||||
unsigned long orig_x0;
|
unsigned long orig_x0;
|
||||||
};
|
};
|
||||||
@@ -169,21 +231,49 @@ struct pt_regs___arm64 {
|
|||||||
#define __PT_PARM3_REG regs[2]
|
#define __PT_PARM3_REG regs[2]
|
||||||
#define __PT_PARM4_REG regs[3]
|
#define __PT_PARM4_REG regs[3]
|
||||||
#define __PT_PARM5_REG regs[4]
|
#define __PT_PARM5_REG regs[4]
|
||||||
|
#define __PT_PARM6_REG regs[5]
|
||||||
|
#define __PT_PARM7_REG regs[6]
|
||||||
|
#define __PT_PARM8_REG regs[7]
|
||||||
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG orig_x0
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||||
|
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||||
|
BPF_CORE_READ((const struct pt_regs___arm64 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||||
|
|
||||||
#define __PT_RET_REG regs[30]
|
#define __PT_RET_REG regs[30]
|
||||||
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
||||||
#define __PT_RC_REG regs[0]
|
#define __PT_RC_REG regs[0]
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG pc
|
#define __PT_IP_REG pc
|
||||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
|
||||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___arm64 *)(x), orig_x0)
|
|
||||||
|
|
||||||
#elif defined(bpf_target_mips)
|
#elif defined(bpf_target_mips)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N64 ABI is assumed right now.
|
||||||
|
* https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions
|
||||||
|
*/
|
||||||
|
|
||||||
#define __PT_PARM1_REG regs[4]
|
#define __PT_PARM1_REG regs[4]
|
||||||
#define __PT_PARM2_REG regs[5]
|
#define __PT_PARM2_REG regs[5]
|
||||||
#define __PT_PARM3_REG regs[6]
|
#define __PT_PARM3_REG regs[6]
|
||||||
#define __PT_PARM4_REG regs[7]
|
#define __PT_PARM4_REG regs[7]
|
||||||
#define __PT_PARM5_REG regs[8]
|
#define __PT_PARM5_REG regs[8]
|
||||||
|
#define __PT_PARM6_REG regs[9]
|
||||||
|
#define __PT_PARM7_REG regs[10]
|
||||||
|
#define __PT_PARM8_REG regs[11]
|
||||||
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG /* only N32/N64 */
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG /* only N32/N64 */
|
||||||
|
|
||||||
#define __PT_RET_REG regs[31]
|
#define __PT_RET_REG regs[31]
|
||||||
#define __PT_FP_REG regs[30] /* Works only with CONFIG_FRAME_POINTER */
|
#define __PT_FP_REG regs[30] /* Works only with CONFIG_FRAME_POINTER */
|
||||||
#define __PT_RC_REG regs[2]
|
#define __PT_RC_REG regs[2]
|
||||||
@@ -192,26 +282,58 @@ struct pt_regs___arm64 {
|
|||||||
|
|
||||||
#elif defined(bpf_target_powerpc)
|
#elif defined(bpf_target_powerpc)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf (page 3-14,
|
||||||
|
* section "Function Calling Sequence")
|
||||||
|
*/
|
||||||
|
|
||||||
#define __PT_PARM1_REG gpr[3]
|
#define __PT_PARM1_REG gpr[3]
|
||||||
#define __PT_PARM2_REG gpr[4]
|
#define __PT_PARM2_REG gpr[4]
|
||||||
#define __PT_PARM3_REG gpr[5]
|
#define __PT_PARM3_REG gpr[5]
|
||||||
#define __PT_PARM4_REG gpr[6]
|
#define __PT_PARM4_REG gpr[6]
|
||||||
#define __PT_PARM5_REG gpr[7]
|
#define __PT_PARM5_REG gpr[7]
|
||||||
|
#define __PT_PARM6_REG gpr[8]
|
||||||
|
#define __PT_PARM7_REG gpr[9]
|
||||||
|
#define __PT_PARM8_REG gpr[10]
|
||||||
|
|
||||||
|
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||||
|
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||||
|
#define __PT_PARM1_SYSCALL_REG orig_gpr3
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
#if !defined(__arch64__)
|
||||||
|
#define __PT_PARM7_SYSCALL_REG __PT_PARM7_REG /* only powerpc (not powerpc64) */
|
||||||
|
#endif
|
||||||
|
|
||||||
#define __PT_RET_REG regs[31]
|
#define __PT_RET_REG regs[31]
|
||||||
#define __PT_FP_REG __unsupported__
|
#define __PT_FP_REG __unsupported__
|
||||||
#define __PT_RC_REG gpr[3]
|
#define __PT_RC_REG gpr[3]
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG nip
|
#define __PT_IP_REG nip
|
||||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
|
||||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
|
||||||
|
|
||||||
#elif defined(bpf_target_sparc)
|
#elif defined(bpf_target_sparc)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://en.wikipedia.org/wiki/Calling_convention#SPARC
|
||||||
|
*/
|
||||||
|
|
||||||
#define __PT_PARM1_REG u_regs[UREG_I0]
|
#define __PT_PARM1_REG u_regs[UREG_I0]
|
||||||
#define __PT_PARM2_REG u_regs[UREG_I1]
|
#define __PT_PARM2_REG u_regs[UREG_I1]
|
||||||
#define __PT_PARM3_REG u_regs[UREG_I2]
|
#define __PT_PARM3_REG u_regs[UREG_I2]
|
||||||
#define __PT_PARM4_REG u_regs[UREG_I3]
|
#define __PT_PARM4_REG u_regs[UREG_I3]
|
||||||
#define __PT_PARM5_REG u_regs[UREG_I4]
|
#define __PT_PARM5_REG u_regs[UREG_I4]
|
||||||
|
#define __PT_PARM6_REG u_regs[UREG_I5]
|
||||||
|
|
||||||
|
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||||
|
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||||
|
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
#define __PT_RET_REG u_regs[UREG_I7]
|
#define __PT_RET_REG u_regs[UREG_I7]
|
||||||
#define __PT_FP_REG __unsupported__
|
#define __PT_FP_REG __unsupported__
|
||||||
#define __PT_RC_REG u_regs[UREG_I0]
|
#define __PT_RC_REG u_regs[UREG_I0]
|
||||||
@@ -225,22 +347,42 @@ struct pt_regs___arm64 {
|
|||||||
|
|
||||||
#elif defined(bpf_target_riscv)
|
#elif defined(bpf_target_riscv)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions
|
||||||
|
*/
|
||||||
|
|
||||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||||
#define __PT_PARM1_REG a0
|
#define __PT_PARM1_REG a0
|
||||||
#define __PT_PARM2_REG a1
|
#define __PT_PARM2_REG a1
|
||||||
#define __PT_PARM3_REG a2
|
#define __PT_PARM3_REG a2
|
||||||
#define __PT_PARM4_REG a3
|
#define __PT_PARM4_REG a3
|
||||||
#define __PT_PARM5_REG a4
|
#define __PT_PARM5_REG a4
|
||||||
#define __PT_RET_REG ra
|
#define __PT_PARM6_REG a5
|
||||||
#define __PT_FP_REG s0
|
#define __PT_PARM7_REG a6
|
||||||
#define __PT_RC_REG a5
|
#define __PT_PARM8_REG a7
|
||||||
#define __PT_SP_REG sp
|
|
||||||
#define __PT_IP_REG pc
|
|
||||||
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
#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
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
|
#define __PT_RET_REG ra
|
||||||
|
#define __PT_FP_REG s0
|
||||||
|
#define __PT_RC_REG a0
|
||||||
|
#define __PT_SP_REG sp
|
||||||
|
#define __PT_IP_REG pc
|
||||||
|
|
||||||
#elif defined(bpf_target_arc)
|
#elif defined(bpf_target_arc)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Section "Function Calling Sequence" (page 24):
|
||||||
|
* https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */
|
/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||||
#define __PT_PARM1_REG scratch.r0
|
#define __PT_PARM1_REG scratch.r0
|
||||||
@@ -248,13 +390,57 @@ struct pt_regs___arm64 {
|
|||||||
#define __PT_PARM3_REG scratch.r2
|
#define __PT_PARM3_REG scratch.r2
|
||||||
#define __PT_PARM4_REG scratch.r3
|
#define __PT_PARM4_REG scratch.r3
|
||||||
#define __PT_PARM5_REG scratch.r4
|
#define __PT_PARM5_REG scratch.r4
|
||||||
|
#define __PT_PARM6_REG scratch.r5
|
||||||
|
#define __PT_PARM7_REG scratch.r6
|
||||||
|
#define __PT_PARM8_REG scratch.r7
|
||||||
|
|
||||||
|
/* arc 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
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
#define __PT_RET_REG scratch.blink
|
#define __PT_RET_REG scratch.blink
|
||||||
#define __PT_FP_REG __unsupported__
|
#define __PT_FP_REG scratch.fp
|
||||||
#define __PT_RC_REG scratch.r0
|
#define __PT_RC_REG scratch.r0
|
||||||
#define __PT_SP_REG scratch.sp
|
#define __PT_SP_REG scratch.sp
|
||||||
#define __PT_IP_REG scratch.ret
|
#define __PT_IP_REG scratch.ret
|
||||||
/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
|
||||||
|
#elif defined(bpf_target_loongarch)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://docs.kernel.org/loongarch/introduction.html
|
||||||
|
* https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* loongarch provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||||
|
#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))
|
||||||
|
#define __PT_PARM1_REG regs[4]
|
||||||
|
#define __PT_PARM2_REG regs[5]
|
||||||
|
#define __PT_PARM3_REG regs[6]
|
||||||
|
#define __PT_PARM4_REG regs[7]
|
||||||
|
#define __PT_PARM5_REG regs[8]
|
||||||
|
#define __PT_PARM6_REG regs[9]
|
||||||
|
#define __PT_PARM7_REG regs[10]
|
||||||
|
#define __PT_PARM8_REG regs[11]
|
||||||
|
|
||||||
|
/* loongarch does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
#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
|
||||||
|
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||||
|
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||||
|
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||||
|
|
||||||
|
#define __PT_RET_REG regs[1]
|
||||||
|
#define __PT_FP_REG regs[22]
|
||||||
|
#define __PT_RC_REG regs[4]
|
||||||
|
#define __PT_SP_REG regs[3]
|
||||||
|
#define __PT_IP_REG csr_era
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -262,16 +448,49 @@ struct pt_regs___arm64 {
|
|||||||
|
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
/* allow some architecutres to override `struct pt_regs` */
|
/* allow some architectures to override `struct pt_regs` */
|
||||||
#ifndef __PT_REGS_CAST
|
#ifndef __PT_REGS_CAST
|
||||||
#define __PT_REGS_CAST(x) (x)
|
#define __PT_REGS_CAST(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Different architectures support different number of arguments passed
|
||||||
|
* through registers. i386 supports just 3, some arches support up to 8.
|
||||||
|
*/
|
||||||
|
#ifndef __PT_PARM4_REG
|
||||||
|
#define __PT_PARM4_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
#ifndef __PT_PARM5_REG
|
||||||
|
#define __PT_PARM5_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
#ifndef __PT_PARM6_REG
|
||||||
|
#define __PT_PARM6_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
#ifndef __PT_PARM7_REG
|
||||||
|
#define __PT_PARM7_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
#ifndef __PT_PARM8_REG
|
||||||
|
#define __PT_PARM8_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Similarly, syscall-specific conventions might differ between function call
|
||||||
|
* conventions within each architecutre. All supported architectures pass
|
||||||
|
* either 6 or 7 syscall arguments in registers.
|
||||||
|
*
|
||||||
|
* See syscall(2) manpage for succinct table with information on each arch.
|
||||||
|
*/
|
||||||
|
#ifndef __PT_PARM7_SYSCALL_REG
|
||||||
|
#define __PT_PARM7_SYSCALL_REG __unsupported__
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
||||||
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
||||||
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
||||||
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
|
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
|
||||||
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
||||||
|
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)
|
||||||
|
#define PT_REGS_PARM7(x) (__PT_REGS_CAST(x)->__PT_PARM7_REG)
|
||||||
|
#define PT_REGS_PARM8(x) (__PT_REGS_CAST(x)->__PT_PARM8_REG)
|
||||||
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
||||||
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
||||||
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
||||||
@@ -283,6 +502,9 @@ struct pt_regs;
|
|||||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG)
|
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG)
|
||||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG)
|
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG)
|
||||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG)
|
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG)
|
||||||
|
#define PT_REGS_PARM6_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_REG)
|
||||||
|
#define PT_REGS_PARM7_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_REG)
|
||||||
|
#define PT_REGS_PARM8_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM8_REG)
|
||||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG)
|
#define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG)
|
||||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG)
|
#define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG)
|
||||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG)
|
#define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG)
|
||||||
@@ -309,24 +531,33 @@ struct pt_regs;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PT_REGS_PARM1_SYSCALL
|
#ifndef PT_REGS_PARM1_SYSCALL
|
||||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1(x)
|
#define PT_REGS_PARM1_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM1_SYSCALL_REG)
|
||||||
|
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_SYSCALL_REG)
|
||||||
|
#endif
|
||||||
|
#ifndef PT_REGS_PARM2_SYSCALL
|
||||||
|
#define PT_REGS_PARM2_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM2_SYSCALL_REG)
|
||||||
|
#define PT_REGS_PARM2_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_SYSCALL_REG)
|
||||||
|
#endif
|
||||||
|
#ifndef PT_REGS_PARM3_SYSCALL
|
||||||
|
#define PT_REGS_PARM3_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM3_SYSCALL_REG)
|
||||||
|
#define PT_REGS_PARM3_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_SYSCALL_REG)
|
||||||
#endif
|
#endif
|
||||||
#define PT_REGS_PARM2_SYSCALL(x) PT_REGS_PARM2(x)
|
|
||||||
#define PT_REGS_PARM3_SYSCALL(x) PT_REGS_PARM3(x)
|
|
||||||
#ifndef PT_REGS_PARM4_SYSCALL
|
#ifndef PT_REGS_PARM4_SYSCALL
|
||||||
#define PT_REGS_PARM4_SYSCALL(x) PT_REGS_PARM4(x)
|
#define PT_REGS_PARM4_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM4_SYSCALL_REG)
|
||||||
|
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_SYSCALL_REG)
|
||||||
#endif
|
#endif
|
||||||
#define PT_REGS_PARM5_SYSCALL(x) PT_REGS_PARM5(x)
|
#ifndef PT_REGS_PARM5_SYSCALL
|
||||||
|
#define PT_REGS_PARM5_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM5_SYSCALL_REG)
|
||||||
#ifndef PT_REGS_PARM1_CORE_SYSCALL
|
#define PT_REGS_PARM5_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_SYSCALL_REG)
|
||||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) PT_REGS_PARM1_CORE(x)
|
|
||||||
#endif
|
#endif
|
||||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) PT_REGS_PARM2_CORE(x)
|
#ifndef PT_REGS_PARM6_SYSCALL
|
||||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) PT_REGS_PARM3_CORE(x)
|
#define PT_REGS_PARM6_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM6_SYSCALL_REG)
|
||||||
#ifndef PT_REGS_PARM4_CORE_SYSCALL
|
#define PT_REGS_PARM6_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_SYSCALL_REG)
|
||||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) PT_REGS_PARM4_CORE(x)
|
#endif
|
||||||
|
#ifndef PT_REGS_PARM7_SYSCALL
|
||||||
|
#define PT_REGS_PARM7_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM7_SYSCALL_REG)
|
||||||
|
#define PT_REGS_PARM7_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_SYSCALL_REG)
|
||||||
#endif
|
#endif
|
||||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) PT_REGS_PARM5_CORE(x)
|
|
||||||
|
|
||||||
#else /* defined(bpf_target_defined) */
|
#else /* defined(bpf_target_defined) */
|
||||||
|
|
||||||
@@ -335,6 +566,9 @@ struct pt_regs;
|
|||||||
#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM6(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM7(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM8(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
@@ -346,6 +580,9 @@ struct pt_regs;
|
|||||||
#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM6_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM7_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM8_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
@@ -360,12 +597,16 @@ struct pt_regs;
|
|||||||
#define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM6_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM7_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
|
||||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
#define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM6_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
#define PT_REGS_PARM7_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||||
|
|
||||||
#endif /* defined(bpf_target_defined) */
|
#endif /* defined(bpf_target_defined) */
|
||||||
|
|
||||||
@@ -424,7 +665,7 @@ struct pt_regs;
|
|||||||
*/
|
*/
|
||||||
#define BPF_PROG(name, args...) \
|
#define BPF_PROG(name, args...) \
|
||||||
name(unsigned long long *ctx); \
|
name(unsigned long long *ctx); \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(unsigned long long *ctx, ##args); \
|
____##name(unsigned long long *ctx, ##args); \
|
||||||
typeof(name(0)) name(unsigned long long *ctx) \
|
typeof(name(0)) name(unsigned long long *ctx) \
|
||||||
{ \
|
{ \
|
||||||
@@ -433,9 +674,116 @@ typeof(name(0)) name(unsigned long long *ctx) \
|
|||||||
return ____##name(___bpf_ctx_cast(args)); \
|
return ____##name(___bpf_ctx_cast(args)); \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
} \
|
} \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(unsigned long long *ctx, ##args)
|
____##name(unsigned long long *ctx, ##args)
|
||||||
|
|
||||||
|
#ifndef ___bpf_nth2
|
||||||
|
#define ___bpf_nth2(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
|
||||||
|
_14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, N, ...) N
|
||||||
|
#endif
|
||||||
|
#ifndef ___bpf_narg2
|
||||||
|
#define ___bpf_narg2(...) \
|
||||||
|
___bpf_nth2(_, ##__VA_ARGS__, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, \
|
||||||
|
6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ___bpf_treg_cnt(t) \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 1, 1, \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 2, 1, \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 4, 1, \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 8, 1, \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 16, 2, \
|
||||||
|
(void)0)))))
|
||||||
|
|
||||||
|
#define ___bpf_reg_cnt0() (0)
|
||||||
|
#define ___bpf_reg_cnt1(t, x) (___bpf_reg_cnt0() + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt2(t, x, args...) (___bpf_reg_cnt1(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt3(t, x, args...) (___bpf_reg_cnt2(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt4(t, x, args...) (___bpf_reg_cnt3(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt5(t, x, args...) (___bpf_reg_cnt4(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt6(t, x, args...) (___bpf_reg_cnt5(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt7(t, x, args...) (___bpf_reg_cnt6(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt8(t, x, args...) (___bpf_reg_cnt7(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt9(t, x, args...) (___bpf_reg_cnt8(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt10(t, x, args...) (___bpf_reg_cnt9(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt11(t, x, args...) (___bpf_reg_cnt10(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt12(t, x, args...) (___bpf_reg_cnt11(args) + ___bpf_treg_cnt(t))
|
||||||
|
#define ___bpf_reg_cnt(args...) ___bpf_apply(___bpf_reg_cnt, ___bpf_narg2(args))(args)
|
||||||
|
|
||||||
|
#define ___bpf_union_arg(t, x, n) \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 1, ({ union { __u8 z[1]; t x; } ___t = { .z = {ctx[n]}}; ___t.x; }), \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 2, ({ union { __u16 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 4, ({ union { __u32 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 8, ({ union { __u64 z[1]; t x; } ___t = {.z = {ctx[n]} }; ___t.x; }), \
|
||||||
|
__builtin_choose_expr(sizeof(t) == 16, ({ union { __u64 z[2]; t x; } ___t = {.z = {ctx[n], ctx[n + 1]} }; ___t.x; }), \
|
||||||
|
(void)0)))))
|
||||||
|
|
||||||
|
#define ___bpf_ctx_arg0(n, args...)
|
||||||
|
#define ___bpf_ctx_arg1(n, t, x) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt1(t, x))
|
||||||
|
#define ___bpf_ctx_arg2(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt2(t, x, args)) ___bpf_ctx_arg1(n, args)
|
||||||
|
#define ___bpf_ctx_arg3(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt3(t, x, args)) ___bpf_ctx_arg2(n, args)
|
||||||
|
#define ___bpf_ctx_arg4(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt4(t, x, args)) ___bpf_ctx_arg3(n, args)
|
||||||
|
#define ___bpf_ctx_arg5(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt5(t, x, args)) ___bpf_ctx_arg4(n, args)
|
||||||
|
#define ___bpf_ctx_arg6(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt6(t, x, args)) ___bpf_ctx_arg5(n, args)
|
||||||
|
#define ___bpf_ctx_arg7(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt7(t, x, args)) ___bpf_ctx_arg6(n, args)
|
||||||
|
#define ___bpf_ctx_arg8(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt8(t, x, args)) ___bpf_ctx_arg7(n, args)
|
||||||
|
#define ___bpf_ctx_arg9(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt9(t, x, args)) ___bpf_ctx_arg8(n, args)
|
||||||
|
#define ___bpf_ctx_arg10(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt10(t, x, args)) ___bpf_ctx_arg9(n, args)
|
||||||
|
#define ___bpf_ctx_arg11(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt11(t, x, args)) ___bpf_ctx_arg10(n, args)
|
||||||
|
#define ___bpf_ctx_arg12(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt12(t, x, args)) ___bpf_ctx_arg11(n, args)
|
||||||
|
#define ___bpf_ctx_arg(args...) ___bpf_apply(___bpf_ctx_arg, ___bpf_narg2(args))(___bpf_reg_cnt(args), args)
|
||||||
|
|
||||||
|
#define ___bpf_ctx_decl0()
|
||||||
|
#define ___bpf_ctx_decl1(t, x) , t x
|
||||||
|
#define ___bpf_ctx_decl2(t, x, args...) , t x ___bpf_ctx_decl1(args)
|
||||||
|
#define ___bpf_ctx_decl3(t, x, args...) , t x ___bpf_ctx_decl2(args)
|
||||||
|
#define ___bpf_ctx_decl4(t, x, args...) , t x ___bpf_ctx_decl3(args)
|
||||||
|
#define ___bpf_ctx_decl5(t, x, args...) , t x ___bpf_ctx_decl4(args)
|
||||||
|
#define ___bpf_ctx_decl6(t, x, args...) , t x ___bpf_ctx_decl5(args)
|
||||||
|
#define ___bpf_ctx_decl7(t, x, args...) , t x ___bpf_ctx_decl6(args)
|
||||||
|
#define ___bpf_ctx_decl8(t, x, args...) , t x ___bpf_ctx_decl7(args)
|
||||||
|
#define ___bpf_ctx_decl9(t, x, args...) , t x ___bpf_ctx_decl8(args)
|
||||||
|
#define ___bpf_ctx_decl10(t, x, args...) , t x ___bpf_ctx_decl9(args)
|
||||||
|
#define ___bpf_ctx_decl11(t, x, args...) , t x ___bpf_ctx_decl10(args)
|
||||||
|
#define ___bpf_ctx_decl12(t, x, args...) , t x ___bpf_ctx_decl11(args)
|
||||||
|
#define ___bpf_ctx_decl(args...) ___bpf_apply(___bpf_ctx_decl, ___bpf_narg2(args))(args)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BPF_PROG2 is an enhanced version of BPF_PROG in order to handle struct
|
||||||
|
* arguments. Since each struct argument might take one or two u64 values
|
||||||
|
* in the trampoline stack, argument type size is needed to place proper number
|
||||||
|
* of u64 values for each argument. Therefore, BPF_PROG2 has different
|
||||||
|
* syntax from BPF_PROG. For example, for the following BPF_PROG syntax:
|
||||||
|
*
|
||||||
|
* int BPF_PROG(test2, int a, int b) { ... }
|
||||||
|
*
|
||||||
|
* the corresponding BPF_PROG2 syntax is:
|
||||||
|
*
|
||||||
|
* int BPF_PROG2(test2, int, a, int, b) { ... }
|
||||||
|
*
|
||||||
|
* where type and the corresponding argument name are separated by comma.
|
||||||
|
*
|
||||||
|
* Use BPF_PROG2 macro if one of the arguments might be a struct/union larger
|
||||||
|
* than 8 bytes:
|
||||||
|
*
|
||||||
|
* int BPF_PROG2(test_struct_arg, struct bpf_testmod_struct_arg_1, a, int, b,
|
||||||
|
* int, c, int, d, struct bpf_testmod_struct_arg_2, e, int, ret)
|
||||||
|
* {
|
||||||
|
* // access a, b, c, d, e, and ret directly
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
#define BPF_PROG2(name, args...) \
|
||||||
|
name(unsigned long long *ctx); \
|
||||||
|
static __always_inline typeof(name(0)) \
|
||||||
|
____##name(unsigned long long *ctx ___bpf_ctx_decl(args)); \
|
||||||
|
typeof(name(0)) name(unsigned long long *ctx) \
|
||||||
|
{ \
|
||||||
|
return ____##name(ctx ___bpf_ctx_arg(args)); \
|
||||||
|
} \
|
||||||
|
static __always_inline typeof(name(0)) \
|
||||||
|
____##name(unsigned long long *ctx ___bpf_ctx_decl(args))
|
||||||
|
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
#define ___bpf_kprobe_args0() ctx
|
#define ___bpf_kprobe_args0() ctx
|
||||||
@@ -444,6 +792,9 @@ struct pt_regs;
|
|||||||
#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
||||||
#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
||||||
#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
||||||
|
#define ___bpf_kprobe_args6(x, args...) ___bpf_kprobe_args5(args), (void *)PT_REGS_PARM6(ctx)
|
||||||
|
#define ___bpf_kprobe_args7(x, args...) ___bpf_kprobe_args6(args), (void *)PT_REGS_PARM7(ctx)
|
||||||
|
#define ___bpf_kprobe_args8(x, args...) ___bpf_kprobe_args7(args), (void *)PT_REGS_PARM8(ctx)
|
||||||
#define ___bpf_kprobe_args(args...) ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
#define ___bpf_kprobe_args(args...) ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -458,7 +809,7 @@ struct pt_regs;
|
|||||||
*/
|
*/
|
||||||
#define BPF_KPROBE(name, args...) \
|
#define BPF_KPROBE(name, args...) \
|
||||||
name(struct pt_regs *ctx); \
|
name(struct pt_regs *ctx); \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args); \
|
____##name(struct pt_regs *ctx, ##args); \
|
||||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||||
{ \
|
{ \
|
||||||
@@ -467,7 +818,7 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
|||||||
return ____##name(___bpf_kprobe_args(args)); \
|
return ____##name(___bpf_kprobe_args(args)); \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
} \
|
} \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args)
|
____##name(struct pt_regs *ctx, ##args)
|
||||||
|
|
||||||
#define ___bpf_kretprobe_args0() ctx
|
#define ___bpf_kretprobe_args0() ctx
|
||||||
@@ -482,7 +833,7 @@ ____##name(struct pt_regs *ctx, ##args)
|
|||||||
*/
|
*/
|
||||||
#define BPF_KRETPROBE(name, args...) \
|
#define BPF_KRETPROBE(name, args...) \
|
||||||
name(struct pt_regs *ctx); \
|
name(struct pt_regs *ctx); \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args); \
|
____##name(struct pt_regs *ctx, ##args); \
|
||||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||||
{ \
|
{ \
|
||||||
@@ -493,39 +844,80 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
|||||||
} \
|
} \
|
||||||
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
||||||
|
|
||||||
|
/* If kernel has CONFIG_ARCH_HAS_SYSCALL_WRAPPER, read pt_regs directly */
|
||||||
#define ___bpf_syscall_args0() ctx
|
#define ___bpf_syscall_args0() ctx
|
||||||
#define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs)
|
#define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_SYSCALL(regs)
|
||||||
#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs)
|
#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_SYSCALL(regs)
|
||||||
#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs)
|
#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_SYSCALL(regs)
|
||||||
#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs)
|
#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_SYSCALL(regs)
|
||||||
#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs)
|
#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_SYSCALL(regs)
|
||||||
|
#define ___bpf_syscall_args6(x, args...) ___bpf_syscall_args5(args), (void *)PT_REGS_PARM6_SYSCALL(regs)
|
||||||
|
#define ___bpf_syscall_args7(x, args...) ___bpf_syscall_args6(args), (void *)PT_REGS_PARM7_SYSCALL(regs)
|
||||||
#define ___bpf_syscall_args(args...) ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args)
|
#define ___bpf_syscall_args(args...) ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args)
|
||||||
|
|
||||||
|
/* If kernel doesn't have CONFIG_ARCH_HAS_SYSCALL_WRAPPER, we have to BPF_CORE_READ from pt_regs */
|
||||||
|
#define ___bpf_syswrap_args0() ctx
|
||||||
|
#define ___bpf_syswrap_args1(x) ___bpf_syswrap_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args2(x, args...) ___bpf_syswrap_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args3(x, args...) ___bpf_syswrap_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args4(x, args...) ___bpf_syswrap_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args5(x, args...) ___bpf_syswrap_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args6(x, args...) ___bpf_syswrap_args5(args), (void *)PT_REGS_PARM6_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args7(x, args...) ___bpf_syswrap_args6(args), (void *)PT_REGS_PARM7_CORE_SYSCALL(regs)
|
||||||
|
#define ___bpf_syswrap_args(args...) ___bpf_apply(___bpf_syswrap_args, ___bpf_narg(args))(args)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BPF_KPROBE_SYSCALL is a variant of BPF_KPROBE, which is intended for
|
* BPF_KSYSCALL is a variant of BPF_KPROBE, which is intended for
|
||||||
* tracing syscall functions, like __x64_sys_close. It hides the underlying
|
* tracing syscall functions, like __x64_sys_close. It hides the underlying
|
||||||
* platform-specific low-level way of getting syscall input arguments from
|
* platform-specific low-level way of getting syscall input arguments from
|
||||||
* struct pt_regs, and provides a familiar typed and named function arguments
|
* struct pt_regs, and provides a familiar typed and named function arguments
|
||||||
* syntax and semantics of accessing syscall input parameters.
|
* syntax and semantics of accessing syscall input parameters.
|
||||||
*
|
*
|
||||||
* Original struct pt_regs* context is preserved as 'ctx' argument. This might
|
* Original struct pt_regs * context is preserved as 'ctx' argument. This might
|
||||||
* be necessary when using BPF helpers like bpf_perf_event_output().
|
* be necessary when using BPF helpers like bpf_perf_event_output().
|
||||||
*
|
*
|
||||||
* This macro relies on BPF CO-RE support.
|
* At the moment BPF_KSYSCALL does not transparently handle all the calling
|
||||||
|
* convention quirks for the following syscalls:
|
||||||
|
*
|
||||||
|
* - mmap(): __ARCH_WANT_SYS_OLD_MMAP.
|
||||||
|
* - clone(): CONFIG_CLONE_BACKWARDS, CONFIG_CLONE_BACKWARDS2 and
|
||||||
|
* CONFIG_CLONE_BACKWARDS3.
|
||||||
|
* - socket-related syscalls: __ARCH_WANT_SYS_SOCKETCALL.
|
||||||
|
* - compat syscalls.
|
||||||
|
*
|
||||||
|
* This may or may not change in the future. User needs to take extra measures
|
||||||
|
* to handle such quirks explicitly, if necessary.
|
||||||
|
*
|
||||||
|
* This macro relies on BPF CO-RE support and virtual __kconfig externs.
|
||||||
*/
|
*/
|
||||||
#define BPF_KPROBE_SYSCALL(name, args...) \
|
#define BPF_KSYSCALL(name, args...) \
|
||||||
name(struct pt_regs *ctx); \
|
name(struct pt_regs *ctx); \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
extern _Bool LINUX_HAS_SYSCALL_WRAPPER __kconfig; \
|
||||||
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args); \
|
____##name(struct pt_regs *ctx, ##args); \
|
||||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||||
{ \
|
{ \
|
||||||
struct pt_regs *regs = PT_REGS_SYSCALL_REGS(ctx); \
|
struct pt_regs *regs = LINUX_HAS_SYSCALL_WRAPPER \
|
||||||
|
? (struct pt_regs *)PT_REGS_PARM1(ctx) \
|
||||||
|
: ctx; \
|
||||||
_Pragma("GCC diagnostic push") \
|
_Pragma("GCC diagnostic push") \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||||
return ____##name(___bpf_syscall_args(args)); \
|
if (LINUX_HAS_SYSCALL_WRAPPER) \
|
||||||
|
return ____##name(___bpf_syswrap_args(args)); \
|
||||||
|
else \
|
||||||
|
return ____##name(___bpf_syscall_args(args)); \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
} \
|
} \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args)
|
____##name(struct pt_regs *ctx, ##args)
|
||||||
|
|
||||||
|
#define BPF_KPROBE_SYSCALL BPF_KSYSCALL
|
||||||
|
|
||||||
|
/* BPF_UPROBE and BPF_URETPROBE are identical to BPF_KPROBE and BPF_KRETPROBE,
|
||||||
|
* but are named way less confusingly for SEC("uprobe") and SEC("uretprobe")
|
||||||
|
* use cases.
|
||||||
|
*/
|
||||||
|
#define BPF_UPROBE(name, args...) BPF_KPROBE(name, ##args)
|
||||||
|
#define BPF_URETPROBE(name, args...) BPF_KRETPROBE(name, ##args)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
332
src/btf.c
@@ -688,8 +688,21 @@ int btf__align_of(const struct btf *btf, __u32 id)
|
|||||||
if (align <= 0)
|
if (align <= 0)
|
||||||
return libbpf_err(align);
|
return libbpf_err(align);
|
||||||
max_align = max(max_align, align);
|
max_align = max(max_align, align);
|
||||||
|
|
||||||
|
/* if field offset isn't aligned according to field
|
||||||
|
* type's alignment, then struct must be packed
|
||||||
|
*/
|
||||||
|
if (btf_member_bitfield_size(t, i) == 0 &&
|
||||||
|
(m->offset % (8 * align)) != 0)
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if struct/union size isn't a multiple of its alignment,
|
||||||
|
* then struct must be packed
|
||||||
|
*/
|
||||||
|
if ((t->size % max_align) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
return max_align;
|
return max_align;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -987,10 +1000,9 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
if (!btf_data) {
|
if (!btf_data) {
|
||||||
err = -ENOENT;
|
pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path);
|
||||||
|
err = -ENODATA;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
|
btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf);
|
||||||
@@ -1225,8 +1237,6 @@ int btf__load_into_kernel(struct btf *btf)
|
|||||||
return btf_load_into_kernel(btf, NULL, 0, 0);
|
return btf_load_into_kernel(btf, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btf__load(struct btf *) __attribute__((alias("btf__load_into_kernel")));
|
|
||||||
|
|
||||||
int btf__fd(const struct btf *btf)
|
int btf__fd(const struct btf *btf)
|
||||||
{
|
{
|
||||||
return btf->fd;
|
return btf->fd;
|
||||||
@@ -1338,9 +1348,9 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
|
|||||||
void *ptr;
|
void *ptr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
|
/* we won't know btf_size until we call bpf_btf_get_info_by_fd(). so
|
||||||
* let's start with a sane default - 4KiB here - and resize it only if
|
* let's start with a sane default - 4KiB here - and resize it only if
|
||||||
* bpf_obj_get_info_by_fd() needs a bigger buffer.
|
* bpf_btf_get_info_by_fd() needs a bigger buffer.
|
||||||
*/
|
*/
|
||||||
last_size = 4096;
|
last_size = 4096;
|
||||||
ptr = malloc(last_size);
|
ptr = malloc(last_size);
|
||||||
@@ -1350,7 +1360,7 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
|
|||||||
memset(&btf_info, 0, sizeof(btf_info));
|
memset(&btf_info, 0, sizeof(btf_info));
|
||||||
btf_info.btf = ptr_to_u64(ptr);
|
btf_info.btf = ptr_to_u64(ptr);
|
||||||
btf_info.btf_size = last_size;
|
btf_info.btf_size = last_size;
|
||||||
err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
|
err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
|
||||||
|
|
||||||
if (!err && btf_info.btf_size > last_size) {
|
if (!err && btf_info.btf_size > last_size) {
|
||||||
void *temp_ptr;
|
void *temp_ptr;
|
||||||
@@ -1368,7 +1378,7 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
|
|||||||
btf_info.btf = ptr_to_u64(ptr);
|
btf_info.btf = ptr_to_u64(ptr);
|
||||||
btf_info.btf_size = last_size;
|
btf_info.btf_size = last_size;
|
||||||
|
|
||||||
err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
|
err = bpf_btf_get_info_by_fd(btf_fd, &btf_info, &len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err || btf_info.btf_size > last_size) {
|
if (err || btf_info.btf_size > last_size) {
|
||||||
@@ -1561,15 +1571,15 @@ struct btf_pipe {
|
|||||||
static int btf_rewrite_str(__u32 *str_off, void *ctx)
|
static int btf_rewrite_str(__u32 *str_off, void *ctx)
|
||||||
{
|
{
|
||||||
struct btf_pipe *p = ctx;
|
struct btf_pipe *p = ctx;
|
||||||
void *mapped_off;
|
long mapped_off;
|
||||||
int off, err;
|
int off, err;
|
||||||
|
|
||||||
if (!*str_off) /* nothing to do for empty strings */
|
if (!*str_off) /* nothing to do for empty strings */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (p->str_off_map &&
|
if (p->str_off_map &&
|
||||||
hashmap__find(p->str_off_map, (void *)(long)*str_off, &mapped_off)) {
|
hashmap__find(p->str_off_map, *str_off, &mapped_off)) {
|
||||||
*str_off = (__u32)(long)mapped_off;
|
*str_off = mapped_off;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1581,7 +1591,7 @@ static int btf_rewrite_str(__u32 *str_off, void *ctx)
|
|||||||
* performing expensive string comparisons.
|
* performing expensive string comparisons.
|
||||||
*/
|
*/
|
||||||
if (p->str_off_map) {
|
if (p->str_off_map) {
|
||||||
err = hashmap__append(p->str_off_map, (void *)(long)*str_off, (void *)(long)off);
|
err = hashmap__append(p->str_off_map, *str_off, off);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1632,8 +1642,8 @@ static int btf_rewrite_type_ids(__u32 *type_id, void *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx);
|
static size_t btf_dedup_identity_hash_fn(long key, void *ctx);
|
||||||
static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx);
|
static bool btf_dedup_equal_fn(long k1, long k2, void *ctx);
|
||||||
|
|
||||||
int btf__add_btf(struct btf *btf, const struct btf *src_btf)
|
int btf__add_btf(struct btf *btf, const struct btf *src_btf)
|
||||||
{
|
{
|
||||||
@@ -1726,7 +1736,8 @@ err_out:
|
|||||||
memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
|
memset(btf->strs_data + old_strs_len, 0, btf->hdr->str_len - old_strs_len);
|
||||||
|
|
||||||
/* and now restore original strings section size; types data size
|
/* and now restore original strings section size; types data size
|
||||||
* wasn't modified, so doesn't need restoring, see big comment above */
|
* wasn't modified, so doesn't need restoring, see big comment above
|
||||||
|
*/
|
||||||
btf->hdr->str_len = old_strs_len;
|
btf->hdr->str_len = old_strs_len;
|
||||||
|
|
||||||
hashmap__free(p.str_off_map);
|
hashmap__free(p.str_off_map);
|
||||||
@@ -2331,7 +2342,7 @@ int btf__add_restrict(struct btf *btf, int ref_type_id)
|
|||||||
*/
|
*/
|
||||||
int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
|
int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
|
||||||
{
|
{
|
||||||
if (!value|| !value[0])
|
if (!value || !value[0])
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
|
return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
|
||||||
@@ -2883,6 +2894,7 @@ static int btf_dedup_strings(struct btf_dedup *d);
|
|||||||
static int btf_dedup_prim_types(struct btf_dedup *d);
|
static int btf_dedup_prim_types(struct btf_dedup *d);
|
||||||
static int btf_dedup_struct_types(struct btf_dedup *d);
|
static int btf_dedup_struct_types(struct btf_dedup *d);
|
||||||
static int btf_dedup_ref_types(struct btf_dedup *d);
|
static int btf_dedup_ref_types(struct btf_dedup *d);
|
||||||
|
static int btf_dedup_resolve_fwds(struct btf_dedup *d);
|
||||||
static int btf_dedup_compact_types(struct btf_dedup *d);
|
static int btf_dedup_compact_types(struct btf_dedup *d);
|
||||||
static int btf_dedup_remap_types(struct btf_dedup *d);
|
static int btf_dedup_remap_types(struct btf_dedup *d);
|
||||||
|
|
||||||
@@ -2990,15 +3002,16 @@ static int btf_dedup_remap_types(struct btf_dedup *d);
|
|||||||
* Algorithm summary
|
* Algorithm summary
|
||||||
* =================
|
* =================
|
||||||
*
|
*
|
||||||
* Algorithm completes its work in 6 separate passes:
|
* Algorithm completes its work in 7 separate passes:
|
||||||
*
|
*
|
||||||
* 1. Strings deduplication.
|
* 1. Strings deduplication.
|
||||||
* 2. Primitive types deduplication (int, enum, fwd).
|
* 2. Primitive types deduplication (int, enum, fwd).
|
||||||
* 3. Struct/union types deduplication.
|
* 3. Struct/union types deduplication.
|
||||||
* 4. Reference types deduplication (pointers, typedefs, arrays, funcs, func
|
* 4. Resolve unambiguous forward declarations.
|
||||||
|
* 5. Reference types deduplication (pointers, typedefs, arrays, funcs, func
|
||||||
* protos, and const/volatile/restrict modifiers).
|
* protos, and const/volatile/restrict modifiers).
|
||||||
* 5. Types compaction.
|
* 6. Types compaction.
|
||||||
* 6. Types remapping.
|
* 7. Types remapping.
|
||||||
*
|
*
|
||||||
* Algorithm determines canonical type descriptor, which is a single
|
* Algorithm determines canonical type descriptor, which is a single
|
||||||
* representative type for each truly unique type. This canonical type is the
|
* representative type for each truly unique type. This canonical type is the
|
||||||
@@ -3062,6 +3075,11 @@ int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts)
|
|||||||
pr_debug("btf_dedup_struct_types failed:%d\n", err);
|
pr_debug("btf_dedup_struct_types failed:%d\n", err);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
err = btf_dedup_resolve_fwds(d);
|
||||||
|
if (err < 0) {
|
||||||
|
pr_debug("btf_dedup_resolve_fwds failed:%d\n", err);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
err = btf_dedup_ref_types(d);
|
err = btf_dedup_ref_types(d);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_debug("btf_dedup_ref_types failed:%d\n", err);
|
pr_debug("btf_dedup_ref_types failed:%d\n", err);
|
||||||
@@ -3128,12 +3146,11 @@ static long hash_combine(long h, long value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define for_each_dedup_cand(d, node, hash) \
|
#define for_each_dedup_cand(d, node, hash) \
|
||||||
hashmap__for_each_key_entry(d->dedup_table, node, (void *)hash)
|
hashmap__for_each_key_entry(d->dedup_table, node, hash)
|
||||||
|
|
||||||
static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
|
static int btf_dedup_table_add(struct btf_dedup *d, long hash, __u32 type_id)
|
||||||
{
|
{
|
||||||
return hashmap__append(d->dedup_table,
|
return hashmap__append(d->dedup_table, hash, type_id);
|
||||||
(void *)hash, (void *)(long)type_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btf_dedup_hypot_map_add(struct btf_dedup *d,
|
static int btf_dedup_hypot_map_add(struct btf_dedup *d,
|
||||||
@@ -3180,17 +3197,17 @@ static void btf_dedup_free(struct btf_dedup *d)
|
|||||||
free(d);
|
free(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t btf_dedup_identity_hash_fn(const void *key, void *ctx)
|
static size_t btf_dedup_identity_hash_fn(long key, void *ctx)
|
||||||
{
|
{
|
||||||
return (size_t)key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t btf_dedup_collision_hash_fn(const void *key, void *ctx)
|
static size_t btf_dedup_collision_hash_fn(long key, void *ctx)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx)
|
static bool btf_dedup_equal_fn(long k1, long k2, void *ctx)
|
||||||
{
|
{
|
||||||
return k1 == k2;
|
return k1 == k2;
|
||||||
}
|
}
|
||||||
@@ -3406,23 +3423,17 @@ static long btf_hash_enum(struct btf_type *t)
|
|||||||
{
|
{
|
||||||
long h;
|
long h;
|
||||||
|
|
||||||
/* don't hash vlen and enum members to support enum fwd resolving */
|
/* don't hash vlen, enum members and size to support enum fwd resolving */
|
||||||
h = hash_combine(0, t->name_off);
|
h = hash_combine(0, t->name_off);
|
||||||
h = hash_combine(h, t->info & ~0xffff);
|
|
||||||
h = hash_combine(h, t->size);
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check structural equality of two ENUMs. */
|
static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
|
||||||
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
|
||||||
{
|
{
|
||||||
const struct btf_enum *m1, *m2;
|
const struct btf_enum *m1, *m2;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vlen = btf_vlen(t1);
|
vlen = btf_vlen(t1);
|
||||||
m1 = btf_enum(t1);
|
m1 = btf_enum(t1);
|
||||||
m2 = btf_enum(t2);
|
m2 = btf_enum(t2);
|
||||||
@@ -3435,15 +3446,12 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
const struct btf_enum64 *m1, *m2;
|
const struct btf_enum64 *m1, *m2;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vlen = btf_vlen(t1);
|
vlen = btf_vlen(t1);
|
||||||
m1 = btf_enum64(t1);
|
m1 = btf_enum64(t1);
|
||||||
m2 = btf_enum64(t2);
|
m2 = btf_enum64(t2);
|
||||||
@@ -3457,6 +3465,19 @@ static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check structural equality of two ENUMs or ENUM64s. */
|
||||||
|
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
||||||
|
{
|
||||||
|
if (!btf_equal_common(t1, t2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* t1 & t2 kinds are identical because of btf_equal_common */
|
||||||
|
if (btf_kind(t1) == BTF_KIND_ENUM)
|
||||||
|
return btf_equal_enum_members(t1, t2);
|
||||||
|
else
|
||||||
|
return btf_equal_enum64_members(t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool btf_is_enum_fwd(struct btf_type *t)
|
static inline bool btf_is_enum_fwd(struct btf_type *t)
|
||||||
{
|
{
|
||||||
return btf_is_any_enum(t) && btf_vlen(t) == 0;
|
return btf_is_any_enum(t) && btf_vlen(t) == 0;
|
||||||
@@ -3466,21 +3487,14 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
|||||||
{
|
{
|
||||||
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
|
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
|
||||||
return btf_equal_enum(t1, t2);
|
return btf_equal_enum(t1, t2);
|
||||||
/* ignore vlen when comparing */
|
/* At this point either t1 or t2 or both are forward declarations, thus:
|
||||||
|
* - skip comparing vlen because it is zero for forward declarations;
|
||||||
|
* - skip comparing size to allow enum forward declarations
|
||||||
|
* to be compatible with enum64 full declarations;
|
||||||
|
* - skip comparing kind for the same reason.
|
||||||
|
*/
|
||||||
return t1->name_off == t2->name_off &&
|
return t1->name_off == t2->name_off &&
|
||||||
(t1->info & ~0xffff) == (t2->info & ~0xffff) &&
|
btf_is_any_enum(t1) && btf_is_any_enum(t2);
|
||||||
t1->size == t2->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2)
|
|
||||||
{
|
|
||||||
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
|
|
||||||
return btf_equal_enum64(t1, t2);
|
|
||||||
|
|
||||||
/* ignore vlen when comparing */
|
|
||||||
return t1->name_off == t2->name_off &&
|
|
||||||
(t1->info & ~0xffff) == (t2->info & ~0xffff) &&
|
|
||||||
t1->size == t2->size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3755,7 +3769,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
h = btf_hash_int_decl_tag(t);
|
h = btf_hash_int_decl_tag(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_int_tag(t, cand)) {
|
if (btf_equal_int_tag(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -3765,9 +3779,10 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BTF_KIND_ENUM:
|
case BTF_KIND_ENUM:
|
||||||
|
case BTF_KIND_ENUM64:
|
||||||
h = btf_hash_enum(t);
|
h = btf_hash_enum(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_enum(t, cand)) {
|
if (btf_equal_enum(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -3785,32 +3800,11 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BTF_KIND_ENUM64:
|
|
||||||
h = btf_hash_enum(t);
|
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
|
||||||
if (btf_equal_enum64(t, cand)) {
|
|
||||||
new_id = cand_id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (btf_compat_enum64(t, cand)) {
|
|
||||||
if (btf_is_enum_fwd(t)) {
|
|
||||||
/* resolve fwd to full enum */
|
|
||||||
new_id = cand_id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* resolve canonical enum fwd to full enum */
|
|
||||||
d->map[cand_id] = type_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
case BTF_KIND_FLOAT:
|
case BTF_KIND_FLOAT:
|
||||||
h = btf_hash_common(t);
|
h = btf_hash_common(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_common(t, cand)) {
|
if (btf_equal_common(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -3889,14 +3883,14 @@ static inline __u16 btf_fwd_kind(struct btf_type *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if given two types are identical ARRAY definitions */
|
/* Check if given two types are identical ARRAY definitions */
|
||||||
static int btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
|
static bool btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
|
||||||
{
|
{
|
||||||
struct btf_type *t1, *t2;
|
struct btf_type *t1, *t2;
|
||||||
|
|
||||||
t1 = btf_type_by_id(d->btf, id1);
|
t1 = btf_type_by_id(d->btf, id1);
|
||||||
t2 = btf_type_by_id(d->btf, id2);
|
t2 = btf_type_by_id(d->btf, id2);
|
||||||
if (!btf_is_array(t1) || !btf_is_array(t2))
|
if (!btf_is_array(t1) || !btf_is_array(t2))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
return btf_equal_array(t1, t2);
|
return btf_equal_array(t1, t2);
|
||||||
}
|
}
|
||||||
@@ -3920,7 +3914,9 @@ static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id
|
|||||||
m1 = btf_members(t1);
|
m1 = btf_members(t1);
|
||||||
m2 = btf_members(t2);
|
m2 = btf_members(t2);
|
||||||
for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
|
for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
|
||||||
if (m1->type != m2->type)
|
if (m1->type != m2->type &&
|
||||||
|
!btf_dedup_identical_arrays(d, m1->type, m2->type) &&
|
||||||
|
!btf_dedup_identical_structs(d, m1->type, m2->type))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -4099,10 +4095,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
return btf_equal_int_tag(cand_type, canon_type);
|
return btf_equal_int_tag(cand_type, canon_type);
|
||||||
|
|
||||||
case BTF_KIND_ENUM:
|
case BTF_KIND_ENUM:
|
||||||
return btf_compat_enum(cand_type, canon_type);
|
|
||||||
|
|
||||||
case BTF_KIND_ENUM64:
|
case BTF_KIND_ENUM64:
|
||||||
return btf_compat_enum64(cand_type, canon_type);
|
return btf_compat_enum(cand_type, canon_type);
|
||||||
|
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
case BTF_KIND_FLOAT:
|
case BTF_KIND_FLOAT:
|
||||||
@@ -4313,7 +4307,7 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
h = btf_hash_struct(t);
|
h = btf_hash_struct(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
__u32 cand_id = (__u32)(long)hash_entry->value;
|
__u32 cand_id = hash_entry->value;
|
||||||
int eq;
|
int eq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4418,7 +4412,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
h = btf_hash_common(t);
|
h = btf_hash_common(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_common(t, cand)) {
|
if (btf_equal_common(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -4435,7 +4429,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
h = btf_hash_int_decl_tag(t);
|
h = btf_hash_int_decl_tag(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_int_tag(t, cand)) {
|
if (btf_equal_int_tag(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -4459,7 +4453,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
h = btf_hash_array(t);
|
h = btf_hash_array(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_array(t, cand)) {
|
if (btf_equal_array(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -4491,7 +4485,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
h = btf_hash_fnproto(t);
|
h = btf_hash_fnproto(t);
|
||||||
for_each_dedup_cand(d, hash_entry, h) {
|
for_each_dedup_cand(d, hash_entry, h) {
|
||||||
cand_id = (__u32)(long)hash_entry->value;
|
cand_id = hash_entry->value;
|
||||||
cand = btf_type_by_id(d->btf, cand_id);
|
cand = btf_type_by_id(d->btf, cand_id);
|
||||||
if (btf_equal_fnproto(t, cand)) {
|
if (btf_equal_fnproto(t, cand)) {
|
||||||
new_id = cand_id;
|
new_id = cand_id;
|
||||||
@@ -4527,6 +4521,134 @@ static int btf_dedup_ref_types(struct btf_dedup *d)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collect a map from type names to type ids for all canonical structs
|
||||||
|
* and unions. If the same name is shared by several canonical types
|
||||||
|
* use a special value 0 to indicate this fact.
|
||||||
|
*/
|
||||||
|
static int btf_dedup_fill_unique_names_map(struct btf_dedup *d, struct hashmap *names_map)
|
||||||
|
{
|
||||||
|
__u32 nr_types = btf__type_cnt(d->btf);
|
||||||
|
struct btf_type *t;
|
||||||
|
__u32 type_id;
|
||||||
|
__u16 kind;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate over base and split module ids in order to get all
|
||||||
|
* available structs in the map.
|
||||||
|
*/
|
||||||
|
for (type_id = 1; type_id < nr_types; ++type_id) {
|
||||||
|
t = btf_type_by_id(d->btf, type_id);
|
||||||
|
kind = btf_kind(t);
|
||||||
|
|
||||||
|
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip non-canonical types */
|
||||||
|
if (type_id != d->map[type_id])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = hashmap__add(names_map, t->name_off, type_id);
|
||||||
|
if (err == -EEXIST)
|
||||||
|
err = hashmap__set(names_map, t->name_off, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btf_dedup_resolve_fwd(struct btf_dedup *d, struct hashmap *names_map, __u32 type_id)
|
||||||
|
{
|
||||||
|
struct btf_type *t = btf_type_by_id(d->btf, type_id);
|
||||||
|
enum btf_fwd_kind fwd_kind = btf_kflag(t);
|
||||||
|
__u16 cand_kind, kind = btf_kind(t);
|
||||||
|
struct btf_type *cand_t;
|
||||||
|
uintptr_t cand_id;
|
||||||
|
|
||||||
|
if (kind != BTF_KIND_FWD)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Skip if this FWD already has a mapping */
|
||||||
|
if (type_id != d->map[type_id])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!hashmap__find(names_map, t->name_off, &cand_id))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Zero is a special value indicating that name is not unique */
|
||||||
|
if (!cand_id)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cand_t = btf_type_by_id(d->btf, cand_id);
|
||||||
|
cand_kind = btf_kind(cand_t);
|
||||||
|
if ((cand_kind == BTF_KIND_STRUCT && fwd_kind != BTF_FWD_STRUCT) ||
|
||||||
|
(cand_kind == BTF_KIND_UNION && fwd_kind != BTF_FWD_UNION))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
d->map[type_id] = cand_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve unambiguous forward declarations.
|
||||||
|
*
|
||||||
|
* The lion's share of all FWD declarations is resolved during
|
||||||
|
* `btf_dedup_struct_types` phase when different type graphs are
|
||||||
|
* compared against each other. However, if in some compilation unit a
|
||||||
|
* FWD declaration is not a part of a type graph compared against
|
||||||
|
* another type graph that declaration's canonical type would not be
|
||||||
|
* changed. Example:
|
||||||
|
*
|
||||||
|
* CU #1:
|
||||||
|
*
|
||||||
|
* struct foo;
|
||||||
|
* struct foo *some_global;
|
||||||
|
*
|
||||||
|
* CU #2:
|
||||||
|
*
|
||||||
|
* struct foo { int u; };
|
||||||
|
* struct foo *another_global;
|
||||||
|
*
|
||||||
|
* After `btf_dedup_struct_types` the BTF looks as follows:
|
||||||
|
*
|
||||||
|
* [1] STRUCT 'foo' size=4 vlen=1 ...
|
||||||
|
* [2] INT 'int' size=4 ...
|
||||||
|
* [3] PTR '(anon)' type_id=1
|
||||||
|
* [4] FWD 'foo' fwd_kind=struct
|
||||||
|
* [5] PTR '(anon)' type_id=4
|
||||||
|
*
|
||||||
|
* This pass assumes that such FWD declarations should be mapped to
|
||||||
|
* structs or unions with identical name in case if the name is not
|
||||||
|
* ambiguous.
|
||||||
|
*/
|
||||||
|
static int btf_dedup_resolve_fwds(struct btf_dedup *d)
|
||||||
|
{
|
||||||
|
int i, err;
|
||||||
|
struct hashmap *names_map;
|
||||||
|
|
||||||
|
names_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL);
|
||||||
|
if (IS_ERR(names_map))
|
||||||
|
return PTR_ERR(names_map);
|
||||||
|
|
||||||
|
err = btf_dedup_fill_unique_names_map(d, names_map);
|
||||||
|
if (err < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
for (i = 0; i < d->btf->nr_types; i++) {
|
||||||
|
err = btf_dedup_resolve_fwd(d, names_map, d->btf->start_id + i);
|
||||||
|
if (err < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
hashmap__free(names_map);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compact types.
|
* Compact types.
|
||||||
*
|
*
|
||||||
@@ -4644,20 +4766,17 @@ static int btf_dedup_remap_types(struct btf_dedup *d)
|
|||||||
*/
|
*/
|
||||||
struct btf *btf__load_vmlinux_btf(void)
|
struct btf *btf__load_vmlinux_btf(void)
|
||||||
{
|
{
|
||||||
struct {
|
const char *locations[] = {
|
||||||
const char *path_fmt;
|
|
||||||
bool raw_btf;
|
|
||||||
} locations[] = {
|
|
||||||
/* try canonical vmlinux BTF through sysfs first */
|
/* try canonical vmlinux BTF through sysfs first */
|
||||||
{ "/sys/kernel/btf/vmlinux", true /* raw BTF */ },
|
"/sys/kernel/btf/vmlinux",
|
||||||
/* fall back to trying to find vmlinux ELF on disk otherwise */
|
/* fall back to trying to find vmlinux on disk otherwise */
|
||||||
{ "/boot/vmlinux-%1$s" },
|
"/boot/vmlinux-%1$s",
|
||||||
{ "/lib/modules/%1$s/vmlinux-%1$s" },
|
"/lib/modules/%1$s/vmlinux-%1$s",
|
||||||
{ "/lib/modules/%1$s/build/vmlinux" },
|
"/lib/modules/%1$s/build/vmlinux",
|
||||||
{ "/usr/lib/modules/%1$s/kernel/vmlinux" },
|
"/usr/lib/modules/%1$s/kernel/vmlinux",
|
||||||
{ "/usr/lib/debug/boot/vmlinux-%1$s" },
|
"/usr/lib/debug/boot/vmlinux-%1$s",
|
||||||
{ "/usr/lib/debug/boot/vmlinux-%1$s.debug" },
|
"/usr/lib/debug/boot/vmlinux-%1$s.debug",
|
||||||
{ "/usr/lib/debug/lib/modules/%1$s/vmlinux" },
|
"/usr/lib/debug/lib/modules/%1$s/vmlinux",
|
||||||
};
|
};
|
||||||
char path[PATH_MAX + 1];
|
char path[PATH_MAX + 1];
|
||||||
struct utsname buf;
|
struct utsname buf;
|
||||||
@@ -4667,15 +4786,12 @@ struct btf *btf__load_vmlinux_btf(void)
|
|||||||
uname(&buf);
|
uname(&buf);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(locations); i++) {
|
for (i = 0; i < ARRAY_SIZE(locations); i++) {
|
||||||
snprintf(path, PATH_MAX, locations[i].path_fmt, buf.release);
|
snprintf(path, PATH_MAX, locations[i], buf.release);
|
||||||
|
|
||||||
if (access(path, R_OK))
|
if (faccessat(AT_FDCWD, path, R_OK, AT_EACCESS))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (locations[i].raw_btf)
|
btf = btf__parse(path, NULL);
|
||||||
btf = btf__parse_raw(path);
|
|
||||||
else
|
|
||||||
btf = btf__parse_elf(path, NULL);
|
|
||||||
err = libbpf_get_error(btf);
|
err = libbpf_get_error(btf);
|
||||||
pr_debug("loading kernel BTF '%s': %d\n", path, err);
|
pr_debug("loading kernel BTF '%s': %d\n", path, err);
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
26
src/btf.h
@@ -116,7 +116,6 @@ LIBBPF_API struct btf *btf__parse_raw_split(const char *path, struct btf *base_b
|
|||||||
|
|
||||||
LIBBPF_API struct btf *btf__load_vmlinux_btf(void);
|
LIBBPF_API struct btf *btf__load_vmlinux_btf(void);
|
||||||
LIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf);
|
LIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf);
|
||||||
LIBBPF_API struct btf *libbpf_find_kernel_btf(void);
|
|
||||||
|
|
||||||
LIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id);
|
LIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id);
|
||||||
LIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf);
|
LIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf);
|
||||||
@@ -487,6 +486,8 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
|
|||||||
return (struct btf_enum *)(t + 1);
|
return (struct btf_enum *)(t + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct btf_enum64;
|
||||||
|
|
||||||
static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
|
static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
|
||||||
{
|
{
|
||||||
return (struct btf_enum64 *)(t + 1);
|
return (struct btf_enum64 *)(t + 1);
|
||||||
@@ -494,7 +495,28 @@ static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
|
|||||||
|
|
||||||
static inline __u64 btf_enum64_value(const struct btf_enum64 *e)
|
static inline __u64 btf_enum64_value(const struct btf_enum64 *e)
|
||||||
{
|
{
|
||||||
return ((__u64)e->val_hi32 << 32) | e->val_lo32;
|
/* struct btf_enum64 is introduced in Linux 6.0, which is very
|
||||||
|
* bleeding-edge. Here we are avoiding relying on struct btf_enum64
|
||||||
|
* definition coming from kernel UAPI headers to support wider range
|
||||||
|
* of system-wide kernel headers.
|
||||||
|
*
|
||||||
|
* Given this header can be also included from C++ applications, that
|
||||||
|
* further restricts C tricks we can use (like using compatible
|
||||||
|
* anonymous struct). So just treat struct btf_enum64 as
|
||||||
|
* a three-element array of u32 and access second (lo32) and third
|
||||||
|
* (hi32) elements directly.
|
||||||
|
*
|
||||||
|
* For reference, here is a struct btf_enum64 definition:
|
||||||
|
*
|
||||||
|
* const struct btf_enum64 {
|
||||||
|
* __u32 name_off;
|
||||||
|
* __u32 val_lo32;
|
||||||
|
* __u32 val_hi32;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
const __u32 *e64 = (const __u32 *)e;
|
||||||
|
|
||||||
|
return ((__u64)e64[2] << 32) | e64[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct btf_member *btf_members(const struct btf_type *t)
|
static inline struct btf_member *btf_members(const struct btf_type *t)
|
||||||
|
|||||||
245
src/btf_dump.c
@@ -13,6 +13,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -117,14 +118,14 @@ struct btf_dump {
|
|||||||
struct btf_dump_data *typed_dump;
|
struct btf_dump_data *typed_dump;
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t str_hash_fn(const void *key, void *ctx)
|
static size_t str_hash_fn(long key, void *ctx)
|
||||||
{
|
{
|
||||||
return str_hash(key);
|
return str_hash((void *)key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool str_equal_fn(const void *a, const void *b, void *ctx)
|
static bool str_equal_fn(long a, long b, void *ctx)
|
||||||
{
|
{
|
||||||
return strcmp(a, b) == 0;
|
return strcmp((void *)a, (void *)b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
|
static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
|
||||||
@@ -219,6 +220,17 @@ static int btf_dump_resize(struct btf_dump *d)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void btf_dump_free_names(struct hashmap *map)
|
||||||
|
{
|
||||||
|
size_t bkt;
|
||||||
|
struct hashmap_entry *cur;
|
||||||
|
|
||||||
|
hashmap__for_each_entry(map, cur, bkt)
|
||||||
|
free((void *)cur->pkey);
|
||||||
|
|
||||||
|
hashmap__free(map);
|
||||||
|
}
|
||||||
|
|
||||||
void btf_dump__free(struct btf_dump *d)
|
void btf_dump__free(struct btf_dump *d)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -237,8 +249,8 @@ void btf_dump__free(struct btf_dump *d)
|
|||||||
free(d->cached_names);
|
free(d->cached_names);
|
||||||
free(d->emit_queue);
|
free(d->emit_queue);
|
||||||
free(d->decl_stack);
|
free(d->decl_stack);
|
||||||
hashmap__free(d->type_names);
|
btf_dump_free_names(d->type_names);
|
||||||
hashmap__free(d->ident_names);
|
btf_dump_free_names(d->ident_names);
|
||||||
|
|
||||||
free(d);
|
free(d);
|
||||||
}
|
}
|
||||||
@@ -822,14 +834,9 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
|||||||
const struct btf_type *t)
|
const struct btf_type *t)
|
||||||
{
|
{
|
||||||
const struct btf_member *m;
|
const struct btf_member *m;
|
||||||
int align, i, bit_sz;
|
int max_align = 1, align, i, bit_sz;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
|
|
||||||
align = btf__align_of(btf, id);
|
|
||||||
/* size of a non-packed struct has to be a multiple of its alignment*/
|
|
||||||
if (align && t->size % align)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
m = btf_members(t);
|
m = btf_members(t);
|
||||||
vlen = btf_vlen(t);
|
vlen = btf_vlen(t);
|
||||||
/* all non-bitfield fields have to be naturally aligned */
|
/* all non-bitfield fields have to be naturally aligned */
|
||||||
@@ -838,8 +845,11 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
|||||||
bit_sz = btf_member_bitfield_size(t, i);
|
bit_sz = btf_member_bitfield_size(t, i);
|
||||||
if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
|
if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
|
||||||
return true;
|
return true;
|
||||||
|
max_align = max(align, max_align);
|
||||||
}
|
}
|
||||||
|
/* size of a non-packed struct has to be a multiple of its alignment */
|
||||||
|
if (t->size % max_align != 0)
|
||||||
|
return true;
|
||||||
/*
|
/*
|
||||||
* if original struct was marked as packed, but its layout is
|
* if original struct was marked as packed, but its layout is
|
||||||
* naturally aligned, we'll detect that it's not packed
|
* naturally aligned, we'll detect that it's not packed
|
||||||
@@ -847,44 +857,97 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int chip_away_bits(int total, int at_most)
|
|
||||||
{
|
|
||||||
return total % at_most ? : at_most;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void btf_dump_emit_bit_padding(const struct btf_dump *d,
|
static void btf_dump_emit_bit_padding(const struct btf_dump *d,
|
||||||
int cur_off, int m_off, int m_bit_sz,
|
int cur_off, int next_off, int next_align,
|
||||||
int align, int lvl)
|
bool in_bitfield, int lvl)
|
||||||
{
|
{
|
||||||
int off_diff = m_off - cur_off;
|
const struct {
|
||||||
int ptr_bits = d->ptr_sz * 8;
|
const char *name;
|
||||||
|
int bits;
|
||||||
|
} pads[] = {
|
||||||
|
{"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8}
|
||||||
|
};
|
||||||
|
int new_off, pad_bits, bits, i;
|
||||||
|
const char *pad_type;
|
||||||
|
|
||||||
if (off_diff <= 0)
|
if (cur_off >= next_off)
|
||||||
/* no gap */
|
return; /* no gap */
|
||||||
return;
|
|
||||||
if (m_bit_sz == 0 && off_diff < align * 8)
|
|
||||||
/* natural padding will take care of a gap */
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (off_diff > 0) {
|
/* For filling out padding we want to take advantage of
|
||||||
const char *pad_type;
|
* natural alignment rules to minimize unnecessary explicit
|
||||||
int pad_bits;
|
* padding. First, we find the largest type (among long, int,
|
||||||
|
* short, or char) that can be used to force naturally aligned
|
||||||
|
* boundary. Once determined, we'll use such type to fill in
|
||||||
|
* the remaining padding gap. In some cases we can rely on
|
||||||
|
* compiler filling some gaps, but sometimes we need to force
|
||||||
|
* alignment to close natural alignment with markers like
|
||||||
|
* `long: 0` (this is always the case for bitfields). Note
|
||||||
|
* that even if struct itself has, let's say 4-byte alignment
|
||||||
|
* (i.e., it only uses up to int-aligned types), using `long:
|
||||||
|
* X;` explicit padding doesn't actually change struct's
|
||||||
|
* overall alignment requirements, but compiler does take into
|
||||||
|
* account that type's (long, in this example) natural
|
||||||
|
* alignment requirements when adding implicit padding. We use
|
||||||
|
* this fact heavily and don't worry about ruining correct
|
||||||
|
* struct alignment requirement.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(pads); i++) {
|
||||||
|
pad_bits = pads[i].bits;
|
||||||
|
pad_type = pads[i].name;
|
||||||
|
|
||||||
if (ptr_bits > 32 && off_diff > 32) {
|
new_off = roundup(cur_off, pad_bits);
|
||||||
pad_type = "long";
|
if (new_off <= next_off)
|
||||||
pad_bits = chip_away_bits(off_diff, ptr_bits);
|
break;
|
||||||
} else if (off_diff > 16) {
|
}
|
||||||
pad_type = "int";
|
|
||||||
pad_bits = chip_away_bits(off_diff, 32);
|
if (new_off > cur_off && new_off <= next_off) {
|
||||||
} else if (off_diff > 8) {
|
/* We need explicit `<type>: 0` aligning mark if next
|
||||||
pad_type = "short";
|
* field is right on alignment offset and its
|
||||||
pad_bits = chip_away_bits(off_diff, 16);
|
* alignment requirement is less strict than <type>'s
|
||||||
} else {
|
* alignment (so compiler won't naturally align to the
|
||||||
pad_type = "char";
|
* offset we expect), or if subsequent `<type>: X`,
|
||||||
pad_bits = chip_away_bits(off_diff, 8);
|
* will actually completely fit in the remaining hole,
|
||||||
|
* making compiler basically ignore `<type>: X`
|
||||||
|
* completely.
|
||||||
|
*/
|
||||||
|
if (in_bitfield ||
|
||||||
|
(new_off == next_off && roundup(cur_off, next_align * 8) != new_off) ||
|
||||||
|
(new_off != next_off && next_off - new_off <= new_off - cur_off))
|
||||||
|
/* but for bitfields we'll emit explicit bit count */
|
||||||
|
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type,
|
||||||
|
in_bitfield ? new_off - cur_off : 0);
|
||||||
|
cur_off = new_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know we start at naturally aligned offset for a chosen
|
||||||
|
* padding type (long, int, short, or char), and so the rest is just
|
||||||
|
* a straightforward filling of remaining padding gap with full
|
||||||
|
* `<type>: sizeof(<type>);` markers, except for the last one, which
|
||||||
|
* might need smaller than sizeof(<type>) padding.
|
||||||
|
*/
|
||||||
|
while (cur_off != next_off) {
|
||||||
|
bits = min(next_off - cur_off, pad_bits);
|
||||||
|
if (bits == pad_bits) {
|
||||||
|
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
|
||||||
|
cur_off += bits;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* For the remainder padding that doesn't cover entire
|
||||||
|
* pad_type bit length, we pick the smallest necessary type.
|
||||||
|
* This is pure aesthetics, we could have just used `long`,
|
||||||
|
* but having smallest necessary one communicates better the
|
||||||
|
* scale of the padding gap.
|
||||||
|
*/
|
||||||
|
for (i = ARRAY_SIZE(pads) - 1; i >= 0; i--) {
|
||||||
|
pad_type = pads[i].name;
|
||||||
|
pad_bits = pads[i].bits;
|
||||||
|
if (pad_bits < bits)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, bits);
|
||||||
|
cur_off += bits;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
|
|
||||||
off_diff -= pad_bits;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,9 +967,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
|||||||
{
|
{
|
||||||
const struct btf_member *m = btf_members(t);
|
const struct btf_member *m = btf_members(t);
|
||||||
bool is_struct = btf_is_struct(t);
|
bool is_struct = btf_is_struct(t);
|
||||||
int align, i, packed, off = 0;
|
bool packed, prev_bitfield = false;
|
||||||
|
int align, i, off = 0;
|
||||||
__u16 vlen = btf_vlen(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
|
align = btf__align_of(d->btf, id);
|
||||||
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
||||||
|
|
||||||
btf_dump_printf(d, "%s%s%s {",
|
btf_dump_printf(d, "%s%s%s {",
|
||||||
@@ -916,37 +981,47 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
|||||||
|
|
||||||
for (i = 0; i < vlen; i++, m++) {
|
for (i = 0; i < vlen; i++, m++) {
|
||||||
const char *fname;
|
const char *fname;
|
||||||
int m_off, m_sz;
|
int m_off, m_sz, m_align;
|
||||||
|
bool in_bitfield;
|
||||||
|
|
||||||
fname = btf_name_of(d, m->name_off);
|
fname = btf_name_of(d, m->name_off);
|
||||||
m_sz = btf_member_bitfield_size(t, i);
|
m_sz = btf_member_bitfield_size(t, i);
|
||||||
m_off = btf_member_bit_offset(t, i);
|
m_off = btf_member_bit_offset(t, i);
|
||||||
align = packed ? 1 : btf__align_of(d->btf, m->type);
|
m_align = packed ? 1 : btf__align_of(d->btf, m->type);
|
||||||
|
|
||||||
btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
|
in_bitfield = prev_bitfield && m_sz != 0;
|
||||||
|
|
||||||
|
btf_dump_emit_bit_padding(d, off, m_off, m_align, in_bitfield, lvl + 1);
|
||||||
btf_dump_printf(d, "\n%s", pfx(lvl + 1));
|
btf_dump_printf(d, "\n%s", pfx(lvl + 1));
|
||||||
btf_dump_emit_type_decl(d, m->type, fname, lvl + 1);
|
btf_dump_emit_type_decl(d, m->type, fname, lvl + 1);
|
||||||
|
|
||||||
if (m_sz) {
|
if (m_sz) {
|
||||||
btf_dump_printf(d, ": %d", m_sz);
|
btf_dump_printf(d, ": %d", m_sz);
|
||||||
off = m_off + m_sz;
|
off = m_off + m_sz;
|
||||||
|
prev_bitfield = true;
|
||||||
} else {
|
} else {
|
||||||
m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
|
m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
|
||||||
off = m_off + m_sz * 8;
|
off = m_off + m_sz * 8;
|
||||||
|
prev_bitfield = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
btf_dump_printf(d, ";");
|
btf_dump_printf(d, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pad at the end, if necessary */
|
/* pad at the end, if necessary */
|
||||||
if (is_struct) {
|
if (is_struct)
|
||||||
align = packed ? 1 : btf__align_of(d->btf, id);
|
btf_dump_emit_bit_padding(d, off, t->size * 8, align, false, lvl + 1);
|
||||||
btf_dump_emit_bit_padding(d, off, t->size * 8, 0, align,
|
|
||||||
lvl + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vlen)
|
/*
|
||||||
|
* Keep `struct empty {}` on a single line,
|
||||||
|
* only print newline when there are regular or padding fields.
|
||||||
|
*/
|
||||||
|
if (vlen || t->size) {
|
||||||
btf_dump_printf(d, "\n");
|
btf_dump_printf(d, "\n");
|
||||||
btf_dump_printf(d, "%s}", pfx(lvl));
|
btf_dump_printf(d, "%s}", pfx(lvl));
|
||||||
|
} else {
|
||||||
|
btf_dump_printf(d, "}");
|
||||||
|
}
|
||||||
if (packed)
|
if (packed)
|
||||||
btf_dump_printf(d, " __attribute__((packed))");
|
btf_dump_printf(d, " __attribute__((packed))");
|
||||||
}
|
}
|
||||||
@@ -1058,6 +1133,43 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
|||||||
else
|
else
|
||||||
btf_dump_emit_enum64_val(d, t, lvl, vlen);
|
btf_dump_emit_enum64_val(d, t, lvl, vlen);
|
||||||
btf_dump_printf(d, "\n%s}", pfx(lvl));
|
btf_dump_printf(d, "\n%s}", pfx(lvl));
|
||||||
|
|
||||||
|
/* special case enums with special sizes */
|
||||||
|
if (t->size == 1) {
|
||||||
|
/* one-byte enums can be forced with mode(byte) attribute */
|
||||||
|
btf_dump_printf(d, " __attribute__((mode(byte)))");
|
||||||
|
} else if (t->size == 8 && d->ptr_sz == 8) {
|
||||||
|
/* enum can be 8-byte sized if one of the enumerator values
|
||||||
|
* doesn't fit in 32-bit integer, or by adding mode(word)
|
||||||
|
* attribute (but probably only on 64-bit architectures); do
|
||||||
|
* our best here to try to satisfy the contract without adding
|
||||||
|
* unnecessary attributes
|
||||||
|
*/
|
||||||
|
bool needs_word_mode;
|
||||||
|
|
||||||
|
if (btf_is_enum(t)) {
|
||||||
|
/* enum can't represent 64-bit values, so we need word mode */
|
||||||
|
needs_word_mode = true;
|
||||||
|
} else {
|
||||||
|
/* enum64 needs mode(word) if none of its values has
|
||||||
|
* non-zero upper 32-bits (which means that all values
|
||||||
|
* fit in 32-bit integers and won't cause compiler to
|
||||||
|
* bump enum to be 64-bit naturally
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
|
||||||
|
needs_word_mode = true;
|
||||||
|
for (i = 0; i < vlen; i++) {
|
||||||
|
if (btf_enum64(t)[i].val_hi32 != 0) {
|
||||||
|
needs_word_mode = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needs_word_mode)
|
||||||
|
btf_dump_printf(d, " __attribute__((mode(word)))");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
||||||
@@ -1520,11 +1632,22 @@ static void btf_dump_emit_type_cast(struct btf_dump *d, __u32 id,
|
|||||||
static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
|
static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
|
||||||
const char *orig_name)
|
const char *orig_name)
|
||||||
{
|
{
|
||||||
|
char *old_name, *new_name;
|
||||||
size_t dup_cnt = 0;
|
size_t dup_cnt = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
hashmap__find(name_map, orig_name, (void **)&dup_cnt);
|
new_name = strdup(orig_name);
|
||||||
|
if (!new_name)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
(void)hashmap__find(name_map, orig_name, &dup_cnt);
|
||||||
dup_cnt++;
|
dup_cnt++;
|
||||||
hashmap__set(name_map, orig_name, (void *)dup_cnt, NULL, NULL);
|
|
||||||
|
err = hashmap__set(name_map, new_name, dup_cnt, &old_name, NULL);
|
||||||
|
if (err)
|
||||||
|
free(new_name);
|
||||||
|
|
||||||
|
free(old_name);
|
||||||
|
|
||||||
return dup_cnt;
|
return dup_cnt;
|
||||||
}
|
}
|
||||||
@@ -1963,7 +2086,7 @@ static int btf_dump_struct_data(struct btf_dump *d,
|
|||||||
{
|
{
|
||||||
const struct btf_member *m = btf_members(t);
|
const struct btf_member *m = btf_members(t);
|
||||||
__u16 n = btf_vlen(t);
|
__u16 n = btf_vlen(t);
|
||||||
int i, err;
|
int i, err = 0;
|
||||||
|
|
||||||
/* note that we increment depth before calling btf_dump_print() below;
|
/* note that we increment depth before calling btf_dump_print() below;
|
||||||
* this is intentional. btf_dump_data_newline() will not print a
|
* this is intentional. btf_dump_data_newline() will not print a
|
||||||
@@ -2045,7 +2168,7 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
|
|||||||
*value = *(__s64 *)data;
|
*value = *(__s64 *)data;
|
||||||
return 0;
|
return 0;
|
||||||
case 4:
|
case 4:
|
||||||
*value = is_signed ? *(__s32 *)data : *(__u32 *)data;
|
*value = is_signed ? (__s64)*(__s32 *)data : *(__u32 *)data;
|
||||||
return 0;
|
return 0;
|
||||||
case 2:
|
case 2:
|
||||||
*value = is_signed ? *(__s16 *)data : *(__u16 *)data;
|
*value = is_signed ? *(__s16 *)data : *(__u16 *)data;
|
||||||
@@ -2385,7 +2508,7 @@ int btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
|
|||||||
d->typed_dump->indent_lvl = OPTS_GET(opts, indent_level, 0);
|
d->typed_dump->indent_lvl = OPTS_GET(opts, indent_level, 0);
|
||||||
|
|
||||||
/* default indent string is a tab */
|
/* default indent string is a tab */
|
||||||
if (!opts->indent_str)
|
if (!OPTS_GET(opts, indent_str, NULL))
|
||||||
d->typed_dump->indent_str[0] = '\t';
|
d->typed_dump->indent_str[0] = '\t';
|
||||||
else
|
else
|
||||||
libbpf_strlcpy(d->typed_dump->indent_str, opts->indent_str,
|
libbpf_strlcpy(d->typed_dump->indent_str, opts->indent_str,
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *attach_name,
|
|||||||
gen->attach_kind = kind;
|
gen->attach_kind = kind;
|
||||||
ret = snprintf(gen->attach_target, sizeof(gen->attach_target), "%s%s",
|
ret = snprintf(gen->attach_target, sizeof(gen->attach_target), "%s%s",
|
||||||
prefix, attach_name);
|
prefix, attach_name);
|
||||||
if (ret == sizeof(gen->attach_target))
|
if (ret >= sizeof(gen->attach_target))
|
||||||
gen->error = -ENOSPC;
|
gen->error = -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ static void emit_find_attach_target(struct bpf_gen *gen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||||
bool is_typeless, int kind, int insn_idx)
|
bool is_typeless, bool is_ld64, int kind, int insn_idx)
|
||||||
{
|
{
|
||||||
struct ksym_relo_desc *relo;
|
struct ksym_relo_desc *relo;
|
||||||
|
|
||||||
@@ -574,6 +574,7 @@ void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
|||||||
relo->name = name;
|
relo->name = name;
|
||||||
relo->is_weak = is_weak;
|
relo->is_weak = is_weak;
|
||||||
relo->is_typeless = is_typeless;
|
relo->is_typeless = is_typeless;
|
||||||
|
relo->is_ld64 = is_ld64;
|
||||||
relo->kind = kind;
|
relo->kind = kind;
|
||||||
relo->insn_idx = insn_idx;
|
relo->insn_idx = insn_idx;
|
||||||
gen->relo_cnt++;
|
gen->relo_cnt++;
|
||||||
@@ -586,9 +587,11 @@ static struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_des
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||||
if (!strcmp(gen->ksyms[i].name, relo->name)) {
|
kdesc = &gen->ksyms[i];
|
||||||
gen->ksyms[i].ref++;
|
if (kdesc->kind == relo->kind && kdesc->is_ld64 == relo->is_ld64 &&
|
||||||
return &gen->ksyms[i];
|
!strcmp(kdesc->name, relo->name)) {
|
||||||
|
kdesc->ref++;
|
||||||
|
return kdesc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kdesc = libbpf_reallocarray(gen->ksyms, gen->nr_ksyms + 1, sizeof(*kdesc));
|
kdesc = libbpf_reallocarray(gen->ksyms, gen->nr_ksyms + 1, sizeof(*kdesc));
|
||||||
@@ -603,6 +606,7 @@ static struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_des
|
|||||||
kdesc->ref = 1;
|
kdesc->ref = 1;
|
||||||
kdesc->off = 0;
|
kdesc->off = 0;
|
||||||
kdesc->insn = 0;
|
kdesc->insn = 0;
|
||||||
|
kdesc->is_ld64 = relo->is_ld64;
|
||||||
return kdesc;
|
return kdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,11 +808,13 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
|||||||
return;
|
return;
|
||||||
/* try to copy from existing ldimm64 insn */
|
/* try to copy from existing ldimm64 insn */
|
||||||
if (kdesc->ref > 1) {
|
if (kdesc->ref > 1) {
|
||||||
move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
|
|
||||||
kdesc->insn + offsetof(struct bpf_insn, imm));
|
|
||||||
move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
|
move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
|
||||||
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
||||||
/* jump over src_reg adjustment if imm is not 0, reuse BPF_REG_0 from move_blob2blob */
|
move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
|
||||||
|
kdesc->insn + offsetof(struct bpf_insn, imm));
|
||||||
|
/* jump over src_reg adjustment if imm (btf_id) is not 0, reuse BPF_REG_0 from move_blob2blob
|
||||||
|
* If btf_id is zero, clear BPF_PSEUDO_BTF_ID flag in src_reg of ld_imm64 insn
|
||||||
|
*/
|
||||||
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 3));
|
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 3));
|
||||||
goto clear_src_reg;
|
goto clear_src_reg;
|
||||||
}
|
}
|
||||||
@@ -831,7 +837,7 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
|||||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7,
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7,
|
||||||
sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
|
sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
|
||||||
/* skip src_reg adjustment */
|
/* skip src_reg adjustment */
|
||||||
emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
|
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 3));
|
||||||
clear_src_reg:
|
clear_src_reg:
|
||||||
/* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */
|
/* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */
|
||||||
reg_mask = src_reg_mask();
|
reg_mask = src_reg_mask();
|
||||||
@@ -862,23 +868,17 @@ static void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn
|
|||||||
{
|
{
|
||||||
int insn;
|
int insn;
|
||||||
|
|
||||||
pr_debug("gen: emit_relo (%d): %s at %d\n", relo->kind, relo->name, relo->insn_idx);
|
pr_debug("gen: emit_relo (%d): %s at %d %s\n",
|
||||||
|
relo->kind, relo->name, relo->insn_idx, relo->is_ld64 ? "ld64" : "call");
|
||||||
insn = insns + sizeof(struct bpf_insn) * relo->insn_idx;
|
insn = insns + sizeof(struct bpf_insn) * relo->insn_idx;
|
||||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn));
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn));
|
||||||
switch (relo->kind) {
|
if (relo->is_ld64) {
|
||||||
case BTF_KIND_VAR:
|
|
||||||
if (relo->is_typeless)
|
if (relo->is_typeless)
|
||||||
emit_relo_ksym_typeless(gen, relo, insn);
|
emit_relo_ksym_typeless(gen, relo, insn);
|
||||||
else
|
else
|
||||||
emit_relo_ksym_btf(gen, relo, insn);
|
emit_relo_ksym_btf(gen, relo, insn);
|
||||||
break;
|
} else {
|
||||||
case BTF_KIND_FUNC:
|
|
||||||
emit_relo_kfunc_btf(gen, relo, insn);
|
emit_relo_kfunc_btf(gen, relo, insn);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pr_warn("Unknown relocation kind '%d'\n", relo->kind);
|
|
||||||
gen->error = -EDOM;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -901,18 +901,20 @@ static void cleanup_core_relo(struct bpf_gen *gen)
|
|||||||
|
|
||||||
static void cleanup_relos(struct bpf_gen *gen, int insns)
|
static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||||
{
|
{
|
||||||
|
struct ksym_desc *kdesc;
|
||||||
int i, insn;
|
int i, insn;
|
||||||
|
|
||||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||||
|
kdesc = &gen->ksyms[i];
|
||||||
/* only close fds for typed ksyms and kfuncs */
|
/* only close fds for typed ksyms and kfuncs */
|
||||||
if (gen->ksyms[i].kind == BTF_KIND_VAR && !gen->ksyms[i].typeless) {
|
if (kdesc->is_ld64 && !kdesc->typeless) {
|
||||||
/* close fd recorded in insn[insn_idx + 1].imm */
|
/* close fd recorded in insn[insn_idx + 1].imm */
|
||||||
insn = gen->ksyms[i].insn;
|
insn = kdesc->insn;
|
||||||
insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm);
|
insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm);
|
||||||
emit_sys_close_blob(gen, insn);
|
emit_sys_close_blob(gen, insn);
|
||||||
} else if (gen->ksyms[i].kind == BTF_KIND_FUNC) {
|
} else if (!kdesc->is_ld64) {
|
||||||
emit_sys_close_blob(gen, blob_fd_array_off(gen, gen->ksyms[i].off));
|
emit_sys_close_blob(gen, blob_fd_array_off(gen, kdesc->off));
|
||||||
if (gen->ksyms[i].off < MAX_FD_ARRAY_SZ)
|
if (kdesc->off < MAX_FD_ARRAY_SZ)
|
||||||
gen->nr_fd_array--;
|
gen->nr_fd_array--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ static int hashmap_grow(struct hashmap *map)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool hashmap_find_entry(const struct hashmap *map,
|
static bool hashmap_find_entry(const struct hashmap *map,
|
||||||
const void *key, size_t hash,
|
const long key, size_t hash,
|
||||||
struct hashmap_entry ***pprev,
|
struct hashmap_entry ***pprev,
|
||||||
struct hashmap_entry **entry)
|
struct hashmap_entry **entry)
|
||||||
{
|
{
|
||||||
@@ -151,18 +151,18 @@ static bool hashmap_find_entry(const struct hashmap *map,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
int hashmap_insert(struct hashmap *map, long key, long value,
|
||||||
enum hashmap_insert_strategy strategy,
|
enum hashmap_insert_strategy strategy,
|
||||||
const void **old_key, void **old_value)
|
long *old_key, long *old_value)
|
||||||
{
|
{
|
||||||
struct hashmap_entry *entry;
|
struct hashmap_entry *entry;
|
||||||
size_t h;
|
size_t h;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (old_key)
|
if (old_key)
|
||||||
*old_key = NULL;
|
*old_key = 0;
|
||||||
if (old_value)
|
if (old_value)
|
||||||
*old_value = NULL;
|
*old_value = 0;
|
||||||
|
|
||||||
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||||
if (strategy != HASHMAP_APPEND &&
|
if (strategy != HASHMAP_APPEND &&
|
||||||
@@ -203,7 +203,7 @@ int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hashmap__find(const struct hashmap *map, const void *key, void **value)
|
bool hashmap_find(const struct hashmap *map, long key, long *value)
|
||||||
{
|
{
|
||||||
struct hashmap_entry *entry;
|
struct hashmap_entry *entry;
|
||||||
size_t h;
|
size_t h;
|
||||||
@@ -217,8 +217,8 @@ bool hashmap__find(const struct hashmap *map, const void *key, void **value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hashmap__delete(struct hashmap *map, const void *key,
|
bool hashmap_delete(struct hashmap *map, long key,
|
||||||
const void **old_key, void **old_value)
|
long *old_key, long *old_value)
|
||||||
{
|
{
|
||||||
struct hashmap_entry **pprev, *entry;
|
struct hashmap_entry **pprev, *entry;
|
||||||
size_t h;
|
size_t h;
|
||||||
|
|||||||
@@ -40,12 +40,32 @@ static inline size_t str_hash(const char *s)
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);
|
typedef size_t (*hashmap_hash_fn)(long key, void *ctx);
|
||||||
typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx);
|
typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hashmap interface is polymorphic, keys and values could be either
|
||||||
|
* long-sized integers or pointers, this is achieved as follows:
|
||||||
|
* - interface functions that operate on keys and values are hidden
|
||||||
|
* behind auxiliary macros, e.g. hashmap_insert <-> hashmap__insert;
|
||||||
|
* - these auxiliary macros cast the key and value parameters as
|
||||||
|
* long or long *, so the user does not have to specify the casts explicitly;
|
||||||
|
* - for pointer parameters (e.g. old_key) the size of the pointed
|
||||||
|
* type is verified by hashmap_cast_ptr using _Static_assert;
|
||||||
|
* - when iterating using hashmap__for_each_* forms
|
||||||
|
* hasmap_entry->key should be used for integer keys and
|
||||||
|
* hasmap_entry->pkey should be used for pointer keys,
|
||||||
|
* same goes for values.
|
||||||
|
*/
|
||||||
struct hashmap_entry {
|
struct hashmap_entry {
|
||||||
const void *key;
|
union {
|
||||||
void *value;
|
long key;
|
||||||
|
const void *pkey;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
long value;
|
||||||
|
void *pvalue;
|
||||||
|
};
|
||||||
struct hashmap_entry *next;
|
struct hashmap_entry *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,6 +122,13 @@ enum hashmap_insert_strategy {
|
|||||||
HASHMAP_APPEND,
|
HASHMAP_APPEND,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define hashmap_cast_ptr(p) ({ \
|
||||||
|
_Static_assert((__builtin_constant_p((p)) ? (p) == NULL : 0) || \
|
||||||
|
sizeof(*(p)) == sizeof(long), \
|
||||||
|
#p " pointee should be a long-sized integer or a pointer"); \
|
||||||
|
(long *)(p); \
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hashmap__insert() adds key/value entry w/ various semantics, depending on
|
* hashmap__insert() adds key/value entry w/ various semantics, depending on
|
||||||
* provided strategy value. If a given key/value pair replaced already
|
* provided strategy value. If a given key/value pair replaced already
|
||||||
@@ -109,42 +136,38 @@ enum hashmap_insert_strategy {
|
|||||||
* through old_key and old_value to allow calling code do proper memory
|
* through old_key and old_value to allow calling code do proper memory
|
||||||
* management.
|
* management.
|
||||||
*/
|
*/
|
||||||
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
int hashmap_insert(struct hashmap *map, long key, long value,
|
||||||
enum hashmap_insert_strategy strategy,
|
enum hashmap_insert_strategy strategy,
|
||||||
const void **old_key, void **old_value);
|
long *old_key, long *old_value);
|
||||||
|
|
||||||
static inline int hashmap__add(struct hashmap *map,
|
#define hashmap__insert(map, key, value, strategy, old_key, old_value) \
|
||||||
const void *key, void *value)
|
hashmap_insert((map), (long)(key), (long)(value), (strategy), \
|
||||||
{
|
hashmap_cast_ptr(old_key), \
|
||||||
return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL);
|
hashmap_cast_ptr(old_value))
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hashmap__set(struct hashmap *map,
|
#define hashmap__add(map, key, value) \
|
||||||
const void *key, void *value,
|
hashmap__insert((map), (key), (value), HASHMAP_ADD, NULL, NULL)
|
||||||
const void **old_key, void **old_value)
|
|
||||||
{
|
|
||||||
return hashmap__insert(map, key, value, HASHMAP_SET,
|
|
||||||
old_key, old_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hashmap__update(struct hashmap *map,
|
#define hashmap__set(map, key, value, old_key, old_value) \
|
||||||
const void *key, void *value,
|
hashmap__insert((map), (key), (value), HASHMAP_SET, (old_key), (old_value))
|
||||||
const void **old_key, void **old_value)
|
|
||||||
{
|
|
||||||
return hashmap__insert(map, key, value, HASHMAP_UPDATE,
|
|
||||||
old_key, old_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hashmap__append(struct hashmap *map,
|
#define hashmap__update(map, key, value, old_key, old_value) \
|
||||||
const void *key, void *value)
|
hashmap__insert((map), (key), (value), HASHMAP_UPDATE, (old_key), (old_value))
|
||||||
{
|
|
||||||
return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hashmap__delete(struct hashmap *map, const void *key,
|
#define hashmap__append(map, key, value) \
|
||||||
const void **old_key, void **old_value);
|
hashmap__insert((map), (key), (value), HASHMAP_APPEND, NULL, NULL)
|
||||||
|
|
||||||
bool hashmap__find(const struct hashmap *map, const void *key, void **value);
|
bool hashmap_delete(struct hashmap *map, long key, long *old_key, long *old_value);
|
||||||
|
|
||||||
|
#define hashmap__delete(map, key, old_key, old_value) \
|
||||||
|
hashmap_delete((map), (long)(key), \
|
||||||
|
hashmap_cast_ptr(old_key), \
|
||||||
|
hashmap_cast_ptr(old_value))
|
||||||
|
|
||||||
|
bool hashmap_find(const struct hashmap *map, long key, long *value);
|
||||||
|
|
||||||
|
#define hashmap__find(map, key, value) \
|
||||||
|
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hashmap__for_each_entry - iterate over all entries in hashmap
|
* hashmap__for_each_entry - iterate over all entries in hashmap
|
||||||
|
|||||||
1533
src/libbpf.c
340
src/libbpf.h
@@ -96,6 +96,14 @@ enum libbpf_print_level {
|
|||||||
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
||||||
const char *, va_list ap);
|
const char *, va_list ap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **libbpf_set_print()** sets user-provided log callback function to
|
||||||
|
* be used for libbpf warnings and informational messages.
|
||||||
|
* @param fn The log print function. If NULL, libbpf won't print anything.
|
||||||
|
* @return Pointer to old print function.
|
||||||
|
*
|
||||||
|
* This function is thread-safe.
|
||||||
|
*/
|
||||||
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
|
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
|
||||||
|
|
||||||
/* Hide internal to user */
|
/* Hide internal to user */
|
||||||
@@ -118,7 +126,9 @@ struct bpf_object_open_opts {
|
|||||||
* auto-pinned to that path on load; defaults to "/sys/fs/bpf".
|
* auto-pinned to that path on load; defaults to "/sys/fs/bpf".
|
||||||
*/
|
*/
|
||||||
const char *pin_root_path;
|
const char *pin_root_path;
|
||||||
long :0;
|
|
||||||
|
__u32 :32; /* stub out now removed attach_prog_fd */
|
||||||
|
|
||||||
/* Additional kernel config content that augments and overrides
|
/* Additional kernel config content that augments and overrides
|
||||||
* system Kconfig for CONFIG_xxx externs.
|
* system Kconfig for CONFIG_xxx externs.
|
||||||
*/
|
*/
|
||||||
@@ -172,6 +182,14 @@ struct bpf_object_open_opts {
|
|||||||
};
|
};
|
||||||
#define bpf_object_open_opts__last_field kernel_log_level
|
#define bpf_object_open_opts__last_field kernel_log_level
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_object__open()** creates a bpf_object by opening
|
||||||
|
* the BPF ELF object file pointed to by the passed path and loading it
|
||||||
|
* into memory.
|
||||||
|
* @param path BPF object file path.
|
||||||
|
* @return pointer to the new bpf_object; or NULL is returned on error,
|
||||||
|
* error code is stored in errno
|
||||||
|
*/
|
||||||
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,16 +219,46 @@ LIBBPF_API struct bpf_object *
|
|||||||
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
|
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
|
||||||
const struct bpf_object_open_opts *opts);
|
const struct bpf_object_open_opts *opts);
|
||||||
|
|
||||||
/* Load/unload object into/from kernel */
|
/**
|
||||||
|
* @brief **bpf_object__load()** loads BPF object into kernel.
|
||||||
|
* @param obj Pointer to a valid BPF object instance returned by
|
||||||
|
* **bpf_object__open*()** APIs
|
||||||
|
* @return 0, on success; negative error code, otherwise, error code is
|
||||||
|
* stored in errno
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
||||||
|
|
||||||
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
/**
|
||||||
|
* @brief **bpf_object__close()** closes a BPF object and releases all
|
||||||
|
* resources.
|
||||||
|
* @param obj Pointer to a valid BPF object
|
||||||
|
*/
|
||||||
|
LIBBPF_API void bpf_object__close(struct bpf_object *obj);
|
||||||
|
|
||||||
/* pin_maps and unpin_maps can both be called with a NULL path, in which case
|
/**
|
||||||
* they will use the pin_path attribute of each map (and ignore all maps that
|
* @brief **bpf_object__pin_maps()** pins each map contained within
|
||||||
* don't have a pin_path set).
|
* the BPF object at the passed directory.
|
||||||
|
* @param obj Pointer to a valid BPF object
|
||||||
|
* @param path A directory where maps should be pinned.
|
||||||
|
* @return 0, on success; negative error code, otherwise
|
||||||
|
*
|
||||||
|
* If `path` is NULL `bpf_map__pin` (which is being used on each map)
|
||||||
|
* will use the pin_path attribute of each map. In this case, maps that
|
||||||
|
* don't have a pin_path set will be ignored.
|
||||||
*/
|
*/
|
||||||
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
|
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_object__unpin_maps()** unpins each map contained within
|
||||||
|
* the BPF object found in the passed directory.
|
||||||
|
* @param obj Pointer to a valid BPF object
|
||||||
|
* @param path A directory where pinned maps should be searched for.
|
||||||
|
* @return 0, on success; negative error code, otherwise
|
||||||
|
*
|
||||||
|
* If `path` is NULL `bpf_map__unpin` (which is being used on each map)
|
||||||
|
* will use the pin_path attribute of each map. In this case, maps that
|
||||||
|
* don't have a pin_path set will be ignored.
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
|
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
|
||||||
const char *path);
|
const char *path);
|
||||||
LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||||
@@ -260,6 +308,8 @@ LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog);
|
|||||||
LIBBPF_API const char *bpf_program__section_name(const struct bpf_program *prog);
|
LIBBPF_API const char *bpf_program__section_name(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);
|
||||||
LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);
|
LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);
|
||||||
|
LIBBPF_API bool bpf_program__autoattach(const struct bpf_program *prog);
|
||||||
|
LIBBPF_API void bpf_program__set_autoattach(struct bpf_program *prog, bool autoattach);
|
||||||
|
|
||||||
struct bpf_insn;
|
struct bpf_insn;
|
||||||
|
|
||||||
@@ -399,12 +449,15 @@ LIBBPF_API struct bpf_link *
|
|||||||
bpf_program__attach(const struct bpf_program *prog);
|
bpf_program__attach(const struct bpf_program *prog);
|
||||||
|
|
||||||
struct bpf_perf_event_opts {
|
struct bpf_perf_event_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
__u64 bpf_cookie;
|
__u64 bpf_cookie;
|
||||||
|
/* don't use BPF link when attach BPF program */
|
||||||
|
bool force_ioctl_attach;
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_perf_event_opts__last_field bpf_cookie
|
#define bpf_perf_event_opts__last_field force_ioctl_attach
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_perf_event(const struct bpf_program *prog, int pfd);
|
bpf_program__attach_perf_event(const struct bpf_program *prog, int pfd);
|
||||||
@@ -413,8 +466,25 @@ LIBBPF_API struct bpf_link *
|
|||||||
bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd,
|
bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd,
|
||||||
const struct bpf_perf_event_opts *opts);
|
const struct bpf_perf_event_opts *opts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum probe_attach_mode - the mode to attach kprobe/uprobe
|
||||||
|
*
|
||||||
|
* force libbpf to attach kprobe/uprobe in specific mode, -ENOTSUP will
|
||||||
|
* be returned if it is not supported by the kernel.
|
||||||
|
*/
|
||||||
|
enum probe_attach_mode {
|
||||||
|
/* attach probe in latest supported mode by kernel */
|
||||||
|
PROBE_ATTACH_MODE_DEFAULT = 0,
|
||||||
|
/* attach probe in legacy mode, using debugfs/tracefs */
|
||||||
|
PROBE_ATTACH_MODE_LEGACY,
|
||||||
|
/* create perf event with perf_event_open() syscall */
|
||||||
|
PROBE_ATTACH_MODE_PERF,
|
||||||
|
/* attach probe with BPF link */
|
||||||
|
PROBE_ATTACH_MODE_LINK,
|
||||||
|
};
|
||||||
|
|
||||||
struct bpf_kprobe_opts {
|
struct bpf_kprobe_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
__u64 bpf_cookie;
|
__u64 bpf_cookie;
|
||||||
@@ -422,9 +492,11 @@ struct bpf_kprobe_opts {
|
|||||||
size_t offset;
|
size_t offset;
|
||||||
/* kprobe is return probe */
|
/* kprobe is return probe */
|
||||||
bool retprobe;
|
bool retprobe;
|
||||||
|
/* kprobe attach mode */
|
||||||
|
enum probe_attach_mode attach_mode;
|
||||||
size_t :0;
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_kprobe_opts__last_field retprobe
|
#define bpf_kprobe_opts__last_field attach_mode
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_kprobe(const struct bpf_program *prog, bool retprobe,
|
bpf_program__attach_kprobe(const struct bpf_program *prog, bool retprobe,
|
||||||
@@ -457,8 +529,54 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
|||||||
const char *pattern,
|
const char *pattern,
|
||||||
const struct bpf_kprobe_multi_opts *opts);
|
const struct bpf_kprobe_multi_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_ksyscall_opts {
|
||||||
|
/* size of this struct, for forward/backward compatibility */
|
||||||
|
size_t sz;
|
||||||
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
/* attach as return probe? */
|
||||||
|
bool retprobe;
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_ksyscall_opts__last_field retprobe
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_program__attach_ksyscall()** attaches a BPF program
|
||||||
|
* to kernel syscall handler of a specified syscall. Optionally it's possible
|
||||||
|
* to request to install retprobe that will be triggered at syscall exit. It's
|
||||||
|
* also possible to associate BPF cookie (though options).
|
||||||
|
*
|
||||||
|
* Libbpf automatically will determine correct full kernel function name,
|
||||||
|
* which depending on system architecture and kernel version/configuration
|
||||||
|
* could be of the form __<arch>_sys_<syscall> or __se_sys_<syscall>, and will
|
||||||
|
* attach specified program using kprobe/kretprobe mechanism.
|
||||||
|
*
|
||||||
|
* **bpf_program__attach_ksyscall()** is an API counterpart of declarative
|
||||||
|
* **SEC("ksyscall/<syscall>")** annotation of BPF programs.
|
||||||
|
*
|
||||||
|
* At the moment **SEC("ksyscall")** and **bpf_program__attach_ksyscall()** do
|
||||||
|
* not handle all the calling convention quirks for mmap(), clone() and compat
|
||||||
|
* syscalls. It also only attaches to "native" syscall interfaces. If host
|
||||||
|
* system supports compat syscalls or defines 32-bit syscalls in 64-bit
|
||||||
|
* kernel, such syscall interfaces won't be attached to by libbpf.
|
||||||
|
*
|
||||||
|
* These limitations may or may not change in the future. Therefore it is
|
||||||
|
* recommended to use SEC("kprobe") for these syscalls or if working with
|
||||||
|
* compat and 32-bit interfaces is required.
|
||||||
|
*
|
||||||
|
* @param prog BPF program to attach
|
||||||
|
* @param syscall_name Symbolic name of the syscall (e.g., "bpf")
|
||||||
|
* @param opts Additional options (see **struct bpf_ksyscall_opts**)
|
||||||
|
* @return Reference to the newly created BPF link; or NULL is returned on
|
||||||
|
* error, error code is stored in errno
|
||||||
|
*/
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_ksyscall(const struct bpf_program *prog,
|
||||||
|
const char *syscall_name,
|
||||||
|
const struct bpf_ksyscall_opts *opts);
|
||||||
|
|
||||||
struct bpf_uprobe_opts {
|
struct bpf_uprobe_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
/* offset of kernel reference counted USDT semaphore, added in
|
/* offset of kernel reference counted USDT semaphore, added in
|
||||||
* a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
* a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
||||||
@@ -476,9 +594,11 @@ struct bpf_uprobe_opts {
|
|||||||
* binary_path.
|
* binary_path.
|
||||||
*/
|
*/
|
||||||
const char *func_name;
|
const char *func_name;
|
||||||
|
/* uprobe attach mode */
|
||||||
|
enum probe_attach_mode attach_mode;
|
||||||
size_t :0;
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_uprobe_opts__last_field func_name
|
#define bpf_uprobe_opts__last_field attach_mode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief **bpf_program__attach_uprobe()** attaches a BPF program
|
* @brief **bpf_program__attach_uprobe()** attaches a BPF program
|
||||||
@@ -552,7 +672,7 @@ bpf_program__attach_usdt(const struct bpf_program *prog,
|
|||||||
const struct bpf_usdt_opts *opts);
|
const struct bpf_usdt_opts *opts);
|
||||||
|
|
||||||
struct bpf_tracepoint_opts {
|
struct bpf_tracepoint_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
__u64 bpf_cookie;
|
__u64 bpf_cookie;
|
||||||
@@ -601,6 +721,7 @@ bpf_program__attach_freplace(const struct bpf_program *prog,
|
|||||||
struct bpf_map;
|
struct bpf_map;
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
||||||
|
LIBBPF_API int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map);
|
||||||
|
|
||||||
struct bpf_iter_attach_opts {
|
struct bpf_iter_attach_opts {
|
||||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
@@ -773,10 +894,57 @@ LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize
|
|||||||
* @return true, if the map is an internal map; false, otherwise
|
* @return true, if the map is an internal map; false, otherwise
|
||||||
*/
|
*/
|
||||||
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__set_pin_path()** sets the path attribute that tells where the
|
||||||
|
* BPF map should be pinned. This does not actually create the 'pin'.
|
||||||
|
* @param map The bpf_map
|
||||||
|
* @param path The path
|
||||||
|
* @return 0, on success; negative error, otherwise
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__pin_path()** gets the path attribute that tells where the
|
||||||
|
* BPF map should be pinned.
|
||||||
|
* @param map The bpf_map
|
||||||
|
* @return The path string; which can be NULL
|
||||||
|
*/
|
||||||
LIBBPF_API const char *bpf_map__pin_path(const struct bpf_map *map);
|
LIBBPF_API const char *bpf_map__pin_path(const struct bpf_map *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__is_pinned()** tells the caller whether or not the
|
||||||
|
* passed map has been pinned via a 'pin' file.
|
||||||
|
* @param map The bpf_map
|
||||||
|
* @return true, if the map is pinned; false, otherwise
|
||||||
|
*/
|
||||||
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__pin()** creates a file that serves as a 'pin'
|
||||||
|
* for the BPF map. This increments the reference count on the
|
||||||
|
* BPF map which will keep the BPF map loaded even after the
|
||||||
|
* userspace process which loaded it has exited.
|
||||||
|
* @param map The bpf_map to pin
|
||||||
|
* @param path A file path for the 'pin'
|
||||||
|
* @return 0, on success; negative error, otherwise
|
||||||
|
*
|
||||||
|
* If `path` is NULL the maps `pin_path` attribute will be used. If this is
|
||||||
|
* also NULL, an error will be returned and the map will not be pinned.
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **bpf_map__unpin()** removes the file that serves as a
|
||||||
|
* 'pin' for the BPF map.
|
||||||
|
* @param map The bpf_map to unpin
|
||||||
|
* @param path A file path for the 'pin'
|
||||||
|
* @return 0, on success; negative error, otherwise
|
||||||
|
*
|
||||||
|
* The `path` parameter can be NULL, in which case the `pin_path`
|
||||||
|
* map attribute is unpinned. If both the `path` parameter and
|
||||||
|
* `pin_path` map attribute are set, they must be equal.
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||||
|
|
||||||
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
||||||
@@ -907,9 +1075,10 @@ struct bpf_xdp_query_opts {
|
|||||||
__u32 hw_prog_id; /* output */
|
__u32 hw_prog_id; /* output */
|
||||||
__u32 skb_prog_id; /* output */
|
__u32 skb_prog_id; /* output */
|
||||||
__u8 attach_mode; /* output */
|
__u8 attach_mode; /* output */
|
||||||
|
__u64 feature_flags; /* output */
|
||||||
size_t :0;
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_xdp_query_opts__last_field attach_mode
|
#define bpf_xdp_query_opts__last_field feature_flags
|
||||||
|
|
||||||
LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags,
|
LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags,
|
||||||
const struct bpf_xdp_attach_opts *opts);
|
const struct bpf_xdp_attach_opts *opts);
|
||||||
@@ -963,11 +1132,12 @@ LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,
|
|||||||
|
|
||||||
/* Ring buffer APIs */
|
/* Ring buffer APIs */
|
||||||
struct ring_buffer;
|
struct ring_buffer;
|
||||||
|
struct user_ring_buffer;
|
||||||
|
|
||||||
typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);
|
typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);
|
||||||
|
|
||||||
struct ring_buffer_opts {
|
struct ring_buffer_opts {
|
||||||
size_t sz; /* size of this struct, for forward/backward compatiblity */
|
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ring_buffer_opts__last_field sz
|
#define ring_buffer_opts__last_field sz
|
||||||
@@ -982,6 +1152,118 @@ 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__consume(struct ring_buffer *rb);
|
||||||
LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);
|
LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);
|
||||||
|
|
||||||
|
struct user_ring_buffer_opts {
|
||||||
|
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define user_ring_buffer_opts__last_field sz
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__new()** creates a new instance of a user ring
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @param map_fd A file descriptor to a BPF_MAP_TYPE_USER_RINGBUF map.
|
||||||
|
* @param opts Options for how the ring buffer should be created.
|
||||||
|
* @return A user ring buffer on success; NULL and errno being set on a
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
LIBBPF_API struct user_ring_buffer *
|
||||||
|
user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__reserve()** reserves a pointer to a sample in the
|
||||||
|
* user ring buffer.
|
||||||
|
* @param rb A pointer to a user ring buffer.
|
||||||
|
* @param size The size of the sample, in bytes.
|
||||||
|
* @return A pointer to an 8-byte aligned reserved region of the user ring
|
||||||
|
* buffer; NULL, and errno being set if a sample could not be reserved.
|
||||||
|
*
|
||||||
|
* This function is *not* thread safe, and callers must synchronize accessing
|
||||||
|
* this function if there are multiple producers. If a size is requested that
|
||||||
|
* is larger than the size of the entire ring buffer, errno will be set to
|
||||||
|
* E2BIG and NULL is returned. If the ring buffer could accommodate the size,
|
||||||
|
* but currently does not have enough space, errno is set to ENOSPC and NULL is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* After initializing the sample, callers must invoke
|
||||||
|
* **user_ring_buffer__submit()** to post the sample to the kernel. Otherwise,
|
||||||
|
* the sample must be freed with **user_ring_buffer__discard()**.
|
||||||
|
*/
|
||||||
|
LIBBPF_API void *user_ring_buffer__reserve(struct user_ring_buffer *rb, __u32 size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__reserve_blocking()** reserves a record in the
|
||||||
|
* ring buffer, possibly blocking for up to @timeout_ms until a sample becomes
|
||||||
|
* available.
|
||||||
|
* @param rb The user ring buffer.
|
||||||
|
* @param size The size of the sample, in bytes.
|
||||||
|
* @param timeout_ms The amount of time, in milliseconds, for which the caller
|
||||||
|
* should block when waiting for a sample. -1 causes the caller to block
|
||||||
|
* indefinitely.
|
||||||
|
* @return A pointer to an 8-byte aligned reserved region of the user ring
|
||||||
|
* buffer; NULL, and errno being set if a sample could not be reserved.
|
||||||
|
*
|
||||||
|
* This function is *not* thread safe, and callers must synchronize
|
||||||
|
* accessing this function if there are multiple producers
|
||||||
|
*
|
||||||
|
* If **timeout_ms** is -1, the function will block indefinitely until a sample
|
||||||
|
* becomes available. Otherwise, **timeout_ms** must be non-negative, or errno
|
||||||
|
* is set to EINVAL, and NULL is returned. If **timeout_ms** is 0, no blocking
|
||||||
|
* will occur and the function will return immediately after attempting to
|
||||||
|
* reserve a sample.
|
||||||
|
*
|
||||||
|
* If **size** is larger than the size of the entire ring buffer, errno is set
|
||||||
|
* to E2BIG and NULL is returned. If the ring buffer could accommodate
|
||||||
|
* **size**, but currently does not have enough space, the caller will block
|
||||||
|
* until at most **timeout_ms** has elapsed. If insufficient space is available
|
||||||
|
* at that time, errno is set to ENOSPC, and NULL is returned.
|
||||||
|
*
|
||||||
|
* The kernel guarantees that it will wake up this thread to check if
|
||||||
|
* sufficient space is available in the ring buffer at least once per
|
||||||
|
* invocation of the **bpf_ringbuf_drain()** helper function, provided that at
|
||||||
|
* least one sample is consumed, and the BPF program did not invoke the
|
||||||
|
* function with BPF_RB_NO_WAKEUP. A wakeup may occur sooner than that, but the
|
||||||
|
* kernel does not guarantee this. If the helper function is invoked with
|
||||||
|
* BPF_RB_FORCE_WAKEUP, a wakeup event will be sent even if no sample is
|
||||||
|
* consumed.
|
||||||
|
*
|
||||||
|
* When a sample of size **size** is found within **timeout_ms**, a pointer to
|
||||||
|
* the sample is returned. After initializing the sample, callers must invoke
|
||||||
|
* **user_ring_buffer__submit()** to post the sample to the ring buffer.
|
||||||
|
* Otherwise, the sample must be freed with **user_ring_buffer__discard()**.
|
||||||
|
*/
|
||||||
|
LIBBPF_API void *user_ring_buffer__reserve_blocking(struct user_ring_buffer *rb,
|
||||||
|
__u32 size,
|
||||||
|
int timeout_ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__submit()** submits a previously reserved sample
|
||||||
|
* into the ring buffer.
|
||||||
|
* @param rb The user ring buffer.
|
||||||
|
* @param sample A reserved sample.
|
||||||
|
*
|
||||||
|
* It is not necessary to synchronize amongst multiple producers when invoking
|
||||||
|
* this function.
|
||||||
|
*/
|
||||||
|
LIBBPF_API void user_ring_buffer__submit(struct user_ring_buffer *rb, void *sample);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__discard()** discards a previously reserved sample.
|
||||||
|
* @param rb The user ring buffer.
|
||||||
|
* @param sample A reserved sample.
|
||||||
|
*
|
||||||
|
* It is not necessary to synchronize amongst multiple producers when invoking
|
||||||
|
* this function.
|
||||||
|
*/
|
||||||
|
LIBBPF_API void user_ring_buffer__discard(struct user_ring_buffer *rb, void *sample);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief **user_ring_buffer__free()** frees a ring buffer that was previously
|
||||||
|
* created with **user_ring_buffer__new()**.
|
||||||
|
* @param rb The user ring buffer being freed.
|
||||||
|
*/
|
||||||
|
LIBBPF_API void user_ring_buffer__free(struct user_ring_buffer *rb);
|
||||||
|
|
||||||
/* Perf buffer APIs */
|
/* Perf buffer APIs */
|
||||||
struct perf_buffer;
|
struct perf_buffer;
|
||||||
|
|
||||||
@@ -992,8 +1274,10 @@ typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
|
|||||||
/* common use perf buffer options */
|
/* common use perf buffer options */
|
||||||
struct perf_buffer_opts {
|
struct perf_buffer_opts {
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
__u32 sample_period;
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define perf_buffer_opts__last_field sz
|
#define perf_buffer_opts__last_field sample_period
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
|
* @brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
|
||||||
@@ -1053,6 +1337,22 @@ LIBBPF_API int perf_buffer__consume(struct perf_buffer *pb);
|
|||||||
LIBBPF_API int perf_buffer__consume_buffer(struct perf_buffer *pb, size_t buf_idx);
|
LIBBPF_API int perf_buffer__consume_buffer(struct perf_buffer *pb, size_t buf_idx);
|
||||||
LIBBPF_API size_t perf_buffer__buffer_cnt(const struct perf_buffer *pb);
|
LIBBPF_API size_t perf_buffer__buffer_cnt(const struct perf_buffer *pb);
|
||||||
LIBBPF_API int perf_buffer__buffer_fd(const struct perf_buffer *pb, size_t buf_idx);
|
LIBBPF_API int perf_buffer__buffer_fd(const struct perf_buffer *pb, size_t buf_idx);
|
||||||
|
/**
|
||||||
|
* @brief **perf_buffer__buffer()** returns the per-cpu raw mmap()'ed underlying
|
||||||
|
* memory region of the ring buffer.
|
||||||
|
* This ring buffer can be used to implement a custom events consumer.
|
||||||
|
* The ring buffer starts with the *struct perf_event_mmap_page*, which
|
||||||
|
* holds the ring buffer managment fields, when accessing the header
|
||||||
|
* structure it's important to be SMP aware.
|
||||||
|
* You can refer to *perf_event_read_simple* for a simple example.
|
||||||
|
* @param pb the perf buffer structure
|
||||||
|
* @param buf_idx the buffer index to retreive
|
||||||
|
* @param buf (out) gets the base pointer of the mmap()'ed memory
|
||||||
|
* @param buf_size (out) gets the size of the mmap()'ed region
|
||||||
|
* @return 0 on success, negative error code for failure
|
||||||
|
*/
|
||||||
|
LIBBPF_API int perf_buffer__buffer(struct perf_buffer *pb, int buf_idx, void **buf,
|
||||||
|
size_t *buf_size);
|
||||||
|
|
||||||
struct bpf_prog_linfo;
|
struct bpf_prog_linfo;
|
||||||
struct bpf_prog_info;
|
struct bpf_prog_info;
|
||||||
@@ -1202,7 +1502,7 @@ LIBBPF_API void
|
|||||||
bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s);
|
bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s);
|
||||||
|
|
||||||
struct gen_loader_opts {
|
struct gen_loader_opts {
|
||||||
size_t sz; /* size of this struct, for forward/backward compatiblity */
|
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||||
const char *data;
|
const char *data;
|
||||||
const char *insns;
|
const char *insns;
|
||||||
__u32 data_sz;
|
__u32 data_sz;
|
||||||
@@ -1220,13 +1520,13 @@ enum libbpf_tristate {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_linker_opts {
|
struct bpf_linker_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
};
|
};
|
||||||
#define bpf_linker_opts__last_field sz
|
#define bpf_linker_opts__last_field sz
|
||||||
|
|
||||||
struct bpf_linker_file_opts {
|
struct bpf_linker_file_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
};
|
};
|
||||||
#define bpf_linker_file_opts__last_field sz
|
#define bpf_linker_file_opts__last_field sz
|
||||||
@@ -1269,7 +1569,7 @@ typedef int (*libbpf_prog_attach_fn_t)(const struct bpf_program *prog, long cook
|
|||||||
struct bpf_link **link);
|
struct bpf_link **link);
|
||||||
|
|
||||||
struct libbpf_prog_handler_opts {
|
struct libbpf_prog_handler_opts {
|
||||||
/* size of this struct, for forward/backward compatiblity */
|
/* size of this struct, for forward/backward compatibility */
|
||||||
size_t sz;
|
size_t sz;
|
||||||
/* User-provided value that is passed to prog_setup_fn,
|
/* User-provided value that is passed to prog_setup_fn,
|
||||||
* prog_prepare_load_fn, and prog_attach_fn callbacks. Allows user to
|
* prog_prepare_load_fn, and prog_attach_fn callbacks. Allows user to
|
||||||
|
|||||||
@@ -355,11 +355,39 @@ LIBBPF_0.8.0 {
|
|||||||
|
|
||||||
LIBBPF_1.0.0 {
|
LIBBPF_1.0.0 {
|
||||||
global:
|
global:
|
||||||
|
bpf_obj_get_opts;
|
||||||
bpf_prog_query_opts;
|
bpf_prog_query_opts;
|
||||||
|
bpf_program__attach_ksyscall;
|
||||||
|
bpf_program__autoattach;
|
||||||
|
bpf_program__set_autoattach;
|
||||||
btf__add_enum64;
|
btf__add_enum64;
|
||||||
btf__add_enum64_value;
|
btf__add_enum64_value;
|
||||||
libbpf_bpf_attach_type_str;
|
libbpf_bpf_attach_type_str;
|
||||||
libbpf_bpf_link_type_str;
|
libbpf_bpf_link_type_str;
|
||||||
libbpf_bpf_map_type_str;
|
libbpf_bpf_map_type_str;
|
||||||
libbpf_bpf_prog_type_str;
|
libbpf_bpf_prog_type_str;
|
||||||
};
|
perf_buffer__buffer;
|
||||||
|
} LIBBPF_0.8.0;
|
||||||
|
|
||||||
|
LIBBPF_1.1.0 {
|
||||||
|
global:
|
||||||
|
bpf_btf_get_fd_by_id_opts;
|
||||||
|
bpf_link_get_fd_by_id_opts;
|
||||||
|
bpf_map_get_fd_by_id_opts;
|
||||||
|
bpf_prog_get_fd_by_id_opts;
|
||||||
|
user_ring_buffer__discard;
|
||||||
|
user_ring_buffer__free;
|
||||||
|
user_ring_buffer__new;
|
||||||
|
user_ring_buffer__reserve;
|
||||||
|
user_ring_buffer__reserve_blocking;
|
||||||
|
user_ring_buffer__submit;
|
||||||
|
} LIBBPF_1.0.0;
|
||||||
|
|
||||||
|
LIBBPF_1.2.0 {
|
||||||
|
global:
|
||||||
|
bpf_btf_get_info_by_fd;
|
||||||
|
bpf_link__update_map;
|
||||||
|
bpf_link_get_info_by_fd;
|
||||||
|
bpf_map_get_info_by_fd;
|
||||||
|
bpf_prog_get_info_by_fd;
|
||||||
|
} LIBBPF_1.1.0;
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
|
|||||||
|
|
||||||
int libbpf_strerror(int err, char *buf, size_t size)
|
int libbpf_strerror(int err, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!buf || !size)
|
if (!buf || !size)
|
||||||
return libbpf_err(-EINVAL);
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
err = err > 0 ? err : -err;
|
err = err > 0 ? err : -err;
|
||||||
|
|
||||||
if (err < __LIBBPF_ERRNO__START) {
|
if (err < __LIBBPF_ERRNO__START) {
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = strerror_r(err, buf, size);
|
ret = strerror_r(err, buf, size);
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
return libbpf_err_errno(ret);
|
return libbpf_err_errno(ret);
|
||||||
@@ -56,12 +56,20 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
|||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
|
msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
|
||||||
snprintf(buf, size, "%s", msg);
|
ret = snprintf(buf, size, "%s", msg);
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
|
/* The length of the buf and msg is positive.
|
||||||
|
* A negative number may be returned only when the
|
||||||
|
* size exceeds INT_MAX. Not likely to appear.
|
||||||
|
*/
|
||||||
|
if (ret >= size)
|
||||||
|
return libbpf_err(-ERANGE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, size, "Unknown libbpf error %d", err);
|
ret = snprintf(buf, size, "Unknown libbpf error %d", err);
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
|
if (ret >= size)
|
||||||
|
return libbpf_err(-ERANGE);
|
||||||
return libbpf_err(-ENOENT);
|
return libbpf_err(-ENOENT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ static inline bool str_has_sfx(const char *str, const char *sfx)
|
|||||||
size_t str_len = strlen(str);
|
size_t str_len = strlen(str);
|
||||||
size_t sfx_len = strlen(sfx);
|
size_t sfx_len = strlen(sfx);
|
||||||
|
|
||||||
if (sfx_len <= str_len)
|
if (sfx_len > str_len)
|
||||||
return strcmp(str + str_len - sfx_len, sfx);
|
return false;
|
||||||
return false;
|
return strcmp(str + str_len - sfx_len, sfx) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Symbol versioning is different between static and shared library.
|
/* Symbol versioning is different between static and shared library.
|
||||||
@@ -352,6 +352,8 @@ enum kern_feature_id {
|
|||||||
FEAT_BPF_COOKIE,
|
FEAT_BPF_COOKIE,
|
||||||
/* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */
|
/* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */
|
||||||
FEAT_BTF_ENUM64,
|
FEAT_BTF_ENUM64,
|
||||||
|
/* Kernel uses syscall wrapper (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) */
|
||||||
|
FEAT_SYSCALL_WRAPPER,
|
||||||
__FEAT_CNT,
|
__FEAT_CNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -541,6 +543,7 @@ static inline int ensure_good_fd(int fd)
|
|||||||
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
close(old_fd);
|
close(old_fd);
|
||||||
|
errno = saved_errno;
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
@@ -571,4 +574,7 @@ static inline bool is_pow_of_2(size_t x)
|
|||||||
return x && (x & (x - 1)) == 0;
|
return x && (x & (x - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PROG_LOAD_ATTEMPTS 5
|
||||||
|
int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts);
|
||||||
|
|
||||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ struct bpf_map;
|
|||||||
struct btf;
|
struct btf;
|
||||||
struct btf_ext;
|
struct btf_ext;
|
||||||
|
|
||||||
|
LIBBPF_API struct btf *libbpf_find_kernel_btf(void);
|
||||||
|
|
||||||
LIBBPF_API enum bpf_prog_type bpf_program__get_type(const struct bpf_program *prog);
|
LIBBPF_API enum bpf_prog_type bpf_program__get_type(const struct bpf_program *prog);
|
||||||
LIBBPF_API enum bpf_attach_type bpf_program__get_expected_attach_type(const struct bpf_program *prog);
|
LIBBPF_API enum bpf_attach_type bpf_program__get_expected_attach_type(const struct bpf_program *prog);
|
||||||
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
||||||
|
|||||||
@@ -12,11 +12,98 @@
|
|||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
#include "bpf.h"
|
#include "bpf.h"
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,
|
||||||
|
* but Ubuntu provides /proc/version_signature file, as described at
|
||||||
|
* https://ubuntu.com/kernel, with an example contents below, which we
|
||||||
|
* can use to get a proper LINUX_VERSION_CODE.
|
||||||
|
*
|
||||||
|
* Ubuntu 5.4.0-12.15-generic 5.4.8
|
||||||
|
*
|
||||||
|
* In the above, 5.4.8 is what kernel is actually expecting, while
|
||||||
|
* uname() call will return 5.4.0 in info.release.
|
||||||
|
*/
|
||||||
|
static __u32 get_ubuntu_kernel_version(void)
|
||||||
|
{
|
||||||
|
const char *ubuntu_kver_file = "/proc/version_signature";
|
||||||
|
__u32 major, minor, patch;
|
||||||
|
int ret;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
f = fopen(ubuntu_kver_file, "r");
|
||||||
|
if (!f)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = fscanf(f, "%*s %*s %u.%u.%u\n", &major, &minor, &patch);
|
||||||
|
fclose(f);
|
||||||
|
if (ret != 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return KERNEL_VERSION(major, minor, patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On Debian LINUX_VERSION_CODE doesn't correspond to info.release.
|
||||||
|
* Instead, it is provided in info.version. An example content of
|
||||||
|
* Debian 10 looks like the below.
|
||||||
|
*
|
||||||
|
* utsname::release 4.19.0-22-amd64
|
||||||
|
* utsname::version #1 SMP Debian 4.19.260-1 (2022-09-29)
|
||||||
|
*
|
||||||
|
* In the above, 4.19.260 is what kernel is actually expecting, while
|
||||||
|
* uname() call will return 4.19.0 in info.release.
|
||||||
|
*/
|
||||||
|
static __u32 get_debian_kernel_version(struct utsname *info)
|
||||||
|
{
|
||||||
|
__u32 major, minor, patch;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = strstr(info->version, "Debian ");
|
||||||
|
if (!p) {
|
||||||
|
/* This is not a Debian kernel. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
else
|
||||||
|
return KERNEL_VERSION(major, minor, patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 get_kernel_version(void)
|
||||||
|
{
|
||||||
|
__u32 major, minor, patch, version;
|
||||||
|
struct utsname info;
|
||||||
|
|
||||||
|
/* Check if this is an Ubuntu kernel. */
|
||||||
|
version = get_ubuntu_kernel_version();
|
||||||
|
if (version != 0)
|
||||||
|
return version;
|
||||||
|
|
||||||
|
uname(&info);
|
||||||
|
|
||||||
|
/* Check if this is a Debian kernel. */
|
||||||
|
version = get_debian_kernel_version(&info);
|
||||||
|
if (version != 0)
|
||||||
|
return version;
|
||||||
|
|
||||||
|
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return KERNEL_VERSION(major, minor, patch);
|
||||||
|
}
|
||||||
|
|
||||||
static int probe_prog_load(enum bpf_prog_type prog_type,
|
static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||||
const struct bpf_insn *insns, size_t insns_cnt,
|
const struct bpf_insn *insns, size_t insns_cnt,
|
||||||
char *log_buf, size_t log_buf_sz)
|
char *log_buf, size_t log_buf_sz)
|
||||||
@@ -193,7 +280,7 @@ static int probe_map_create(enum bpf_map_type map_type)
|
|||||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||||
int key_size, value_size, max_entries;
|
int key_size, value_size, max_entries;
|
||||||
__u32 btf_key_type_id = 0, btf_value_type_id = 0;
|
__u32 btf_key_type_id = 0, btf_value_type_id = 0;
|
||||||
int fd = -1, btf_fd = -1, fd_inner = -1, exp_err = 0, err;
|
int fd = -1, btf_fd = -1, fd_inner = -1, exp_err = 0, err = 0;
|
||||||
|
|
||||||
key_size = sizeof(__u32);
|
key_size = sizeof(__u32);
|
||||||
value_size = sizeof(__u32);
|
value_size = sizeof(__u32);
|
||||||
@@ -221,6 +308,7 @@ static int probe_map_create(enum bpf_map_type map_type)
|
|||||||
case BPF_MAP_TYPE_SK_STORAGE:
|
case BPF_MAP_TYPE_SK_STORAGE:
|
||||||
case BPF_MAP_TYPE_INODE_STORAGE:
|
case BPF_MAP_TYPE_INODE_STORAGE:
|
||||||
case BPF_MAP_TYPE_TASK_STORAGE:
|
case BPF_MAP_TYPE_TASK_STORAGE:
|
||||||
|
case BPF_MAP_TYPE_CGRP_STORAGE:
|
||||||
btf_key_type_id = 1;
|
btf_key_type_id = 1;
|
||||||
btf_value_type_id = 3;
|
btf_value_type_id = 3;
|
||||||
value_size = 8;
|
value_size = 8;
|
||||||
@@ -231,9 +319,10 @@ static int probe_map_create(enum bpf_map_type map_type)
|
|||||||
return btf_fd;
|
return btf_fd;
|
||||||
break;
|
break;
|
||||||
case BPF_MAP_TYPE_RINGBUF:
|
case BPF_MAP_TYPE_RINGBUF:
|
||||||
|
case BPF_MAP_TYPE_USER_RINGBUF:
|
||||||
key_size = 0;
|
key_size = 0;
|
||||||
value_size = 0;
|
value_size = 0;
|
||||||
max_entries = 4096;
|
max_entries = sysconf(_SC_PAGE_SIZE);
|
||||||
break;
|
break;
|
||||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||||
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
#define __LIBBPF_VERSION_H
|
#define __LIBBPF_VERSION_H
|
||||||
|
|
||||||
#define LIBBPF_MAJOR_VERSION 1
|
#define LIBBPF_MAJOR_VERSION 1
|
||||||
#define LIBBPF_MINOR_VERSION 0
|
#define LIBBPF_MINOR_VERSION 2
|
||||||
|
|
||||||
#endif /* __LIBBPF_VERSION_H */
|
#endif /* __LIBBPF_VERSION_H */
|
||||||
|
|||||||
25
src/linker.c
@@ -1115,7 +1115,19 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src
|
|||||||
|
|
||||||
if (src->shdr->sh_type != SHT_NOBITS) {
|
if (src->shdr->sh_type != SHT_NOBITS) {
|
||||||
tmp = realloc(dst->raw_data, dst_final_sz);
|
tmp = realloc(dst->raw_data, dst_final_sz);
|
||||||
if (!tmp)
|
/* If dst_align_sz == 0, realloc() behaves in a special way:
|
||||||
|
* 1. When dst->raw_data is NULL it returns:
|
||||||
|
* "either NULL or a pointer suitable to be passed to free()" [1].
|
||||||
|
* 2. When dst->raw_data is not-NULL it frees dst->raw_data and returns NULL,
|
||||||
|
* thus invalidating any "pointer suitable to be passed to free()" obtained
|
||||||
|
* at step (1).
|
||||||
|
*
|
||||||
|
* The dst_align_sz > 0 check avoids error exit after (2), otherwise
|
||||||
|
* dst->raw_data would be freed again in bpf_linker__free().
|
||||||
|
*
|
||||||
|
* [1] man 3 realloc
|
||||||
|
*/
|
||||||
|
if (!tmp && dst_align_sz > 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
dst->raw_data = tmp;
|
dst->raw_data = tmp;
|
||||||
|
|
||||||
@@ -1997,7 +2009,6 @@ add_sym:
|
|||||||
static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *obj)
|
static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *obj)
|
||||||
{
|
{
|
||||||
struct src_sec *src_symtab = &obj->secs[obj->symtab_sec_idx];
|
struct src_sec *src_symtab = &obj->secs[obj->symtab_sec_idx];
|
||||||
struct dst_sec *dst_symtab;
|
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
for (i = 1; i < obj->sec_cnt; i++) {
|
for (i = 1; i < obj->sec_cnt; i++) {
|
||||||
@@ -2030,9 +2041,6 @@ static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *ob
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add_dst_sec() above could have invalidated linker->secs */
|
|
||||||
dst_symtab = &linker->secs[linker->symtab_sec_idx];
|
|
||||||
|
|
||||||
/* shdr->sh_link points to SYMTAB */
|
/* shdr->sh_link points to SYMTAB */
|
||||||
dst_sec->shdr->sh_link = linker->symtab_sec_idx;
|
dst_sec->shdr->sh_link = linker->symtab_sec_idx;
|
||||||
|
|
||||||
@@ -2049,16 +2057,13 @@ static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *ob
|
|||||||
dst_rel = dst_sec->raw_data + src_sec->dst_off;
|
dst_rel = dst_sec->raw_data + src_sec->dst_off;
|
||||||
n = src_sec->shdr->sh_size / src_sec->shdr->sh_entsize;
|
n = src_sec->shdr->sh_size / src_sec->shdr->sh_entsize;
|
||||||
for (j = 0; j < n; j++, src_rel++, dst_rel++) {
|
for (j = 0; j < n; j++, src_rel++, dst_rel++) {
|
||||||
size_t src_sym_idx = ELF64_R_SYM(src_rel->r_info);
|
size_t src_sym_idx, dst_sym_idx, sym_type;
|
||||||
size_t sym_type = ELF64_R_TYPE(src_rel->r_info);
|
Elf64_Sym *src_sym;
|
||||||
Elf64_Sym *src_sym, *dst_sym;
|
|
||||||
size_t dst_sym_idx;
|
|
||||||
|
|
||||||
src_sym_idx = ELF64_R_SYM(src_rel->r_info);
|
src_sym_idx = ELF64_R_SYM(src_rel->r_info);
|
||||||
src_sym = src_symtab->data->d_buf + sizeof(*src_sym) * src_sym_idx;
|
src_sym = src_symtab->data->d_buf + sizeof(*src_sym) * src_sym_idx;
|
||||||
|
|
||||||
dst_sym_idx = obj->sym_map[src_sym_idx];
|
dst_sym_idx = obj->sym_map[src_sym_idx];
|
||||||
dst_sym = dst_symtab->raw_data + sizeof(*dst_sym) * dst_sym_idx;
|
|
||||||
dst_rel->r_offset += src_linked_sec->dst_off;
|
dst_rel->r_offset += src_linked_sec->dst_off;
|
||||||
sym_type = ELF64_R_TYPE(src_rel->r_info);
|
sym_type = ELF64_R_TYPE(src_rel->r_info);
|
||||||
dst_rel->r_info = ELF64_R_INFO(dst_sym_idx, sym_type);
|
dst_rel->r_info = ELF64_R_INFO(dst_sym_idx, sym_type);
|
||||||
|
|||||||
129
src/netlink.c
@@ -9,6 +9,7 @@
|
|||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/pkt_cls.h>
|
#include <linux/pkt_cls.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <linux/netdev.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -39,9 +40,15 @@ struct xdp_id_md {
|
|||||||
int ifindex;
|
int ifindex;
|
||||||
__u32 flags;
|
__u32 flags;
|
||||||
struct xdp_link_info info;
|
struct xdp_link_info info;
|
||||||
|
__u64 feature_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int libbpf_netlink_open(__u32 *nl_pid)
|
struct xdp_features_md {
|
||||||
|
int ifindex;
|
||||||
|
__u64 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int libbpf_netlink_open(__u32 *nl_pid, int proto)
|
||||||
{
|
{
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
@@ -51,7 +58,7 @@ static int libbpf_netlink_open(__u32 *nl_pid)
|
|||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
sa.nl_family = AF_NETLINK;
|
||||||
|
|
||||||
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@@ -212,14 +219,14 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
|
static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
|
||||||
__dump_nlmsg_t parse_msg,
|
int proto, __dump_nlmsg_t parse_msg,
|
||||||
libbpf_dump_nlmsg_t parse_attr,
|
libbpf_dump_nlmsg_t parse_attr,
|
||||||
void *cookie)
|
void *cookie)
|
||||||
{
|
{
|
||||||
__u32 nl_pid = 0;
|
__u32 nl_pid = 0;
|
||||||
int sock, ret;
|
int sock, ret;
|
||||||
|
|
||||||
sock = libbpf_netlink_open(&nl_pid);
|
sock = libbpf_netlink_open(&nl_pid, proto);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
return sock;
|
return sock;
|
||||||
|
|
||||||
@@ -238,6 +245,43 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_genl_family_id(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||||
|
void *cookie)
|
||||||
|
{
|
||||||
|
struct genlmsghdr *gnl = NLMSG_DATA(nh);
|
||||||
|
struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
|
||||||
|
struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
|
||||||
|
__u16 *id = cookie;
|
||||||
|
|
||||||
|
libbpf_nla_parse(tb, CTRL_ATTR_FAMILY_ID, na,
|
||||||
|
NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
|
||||||
|
if (!tb[CTRL_ATTR_FAMILY_ID])
|
||||||
|
return NL_CONT;
|
||||||
|
|
||||||
|
*id = libbpf_nla_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||||
|
return NL_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libbpf_netlink_resolve_genl_family_id(const char *name,
|
||||||
|
__u16 len, __u16 *id)
|
||||||
|
{
|
||||||
|
struct libbpf_nla_req req = {
|
||||||
|
.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN),
|
||||||
|
.nh.nlmsg_type = GENL_ID_CTRL,
|
||||||
|
.nh.nlmsg_flags = NLM_F_REQUEST,
|
||||||
|
.gnl.cmd = CTRL_CMD_GETFAMILY,
|
||||||
|
.gnl.version = 2,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = nlattr_add(&req, CTRL_ATTR_FAMILY_NAME, name, len);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
|
||||||
|
parse_genl_family_id, NULL, id);
|
||||||
|
}
|
||||||
|
|
||||||
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
||||||
__u32 flags)
|
__u32 flags)
|
||||||
{
|
{
|
||||||
@@ -271,7 +315,7 @@ static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
|||||||
}
|
}
|
||||||
nlattr_end_nested(&req, nla);
|
nlattr_end_nested(&req, nla);
|
||||||
|
|
||||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts)
|
int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts)
|
||||||
@@ -357,6 +401,29 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||||
|
void *cookie)
|
||||||
|
{
|
||||||
|
struct genlmsghdr *gnl = NLMSG_DATA(nh);
|
||||||
|
struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
|
||||||
|
struct nlattr *tb[NETDEV_CMD_MAX + 1];
|
||||||
|
struct xdp_features_md *md = cookie;
|
||||||
|
__u32 ifindex;
|
||||||
|
|
||||||
|
libbpf_nla_parse(tb, NETDEV_CMD_MAX, na,
|
||||||
|
NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
|
||||||
|
|
||||||
|
if (!tb[NETDEV_A_DEV_IFINDEX] || !tb[NETDEV_A_DEV_XDP_FEATURES])
|
||||||
|
return NL_CONT;
|
||||||
|
|
||||||
|
ifindex = libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_IFINDEX]);
|
||||||
|
if (ifindex != md->ifindex)
|
||||||
|
return NL_CONT;
|
||||||
|
|
||||||
|
md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]);
|
||||||
|
return NL_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||||
{
|
{
|
||||||
struct libbpf_nla_req req = {
|
struct libbpf_nla_req req = {
|
||||||
@@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
|||||||
.ifinfo.ifi_family = AF_PACKET,
|
.ifinfo.ifi_family = AF_PACKET,
|
||||||
};
|
};
|
||||||
struct xdp_id_md xdp_id = {};
|
struct xdp_id_md xdp_id = {};
|
||||||
|
struct xdp_features_md md = {
|
||||||
|
.ifindex = ifindex,
|
||||||
|
};
|
||||||
|
__u16 id;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_xdp_query_opts))
|
if (!OPTS_VALID(opts, bpf_xdp_query_opts))
|
||||||
@@ -382,7 +453,7 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
|||||||
xdp_id.ifindex = ifindex;
|
xdp_id.ifindex = ifindex;
|
||||||
xdp_id.flags = xdp_flags;
|
xdp_id.flags = xdp_flags;
|
||||||
|
|
||||||
err = libbpf_netlink_send_recv(&req, __dump_link_nlmsg,
|
err = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, __dump_link_nlmsg,
|
||||||
get_xdp_info, &xdp_id);
|
get_xdp_info, &xdp_id);
|
||||||
if (err)
|
if (err)
|
||||||
return libbpf_err(err);
|
return libbpf_err(err);
|
||||||
@@ -393,6 +464,37 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
|||||||
OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id);
|
OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id);
|
||||||
OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode);
|
OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode);
|
||||||
|
|
||||||
|
if (!OPTS_HAS(opts, feature_flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id);
|
||||||
|
if (err < 0) {
|
||||||
|
if (err == -ENOENT) {
|
||||||
|
opts->feature_flags = 0;
|
||||||
|
goto skip_feature_flags;
|
||||||
|
}
|
||||||
|
return libbpf_err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
|
||||||
|
req.nh.nlmsg_flags = NLM_F_REQUEST;
|
||||||
|
req.nh.nlmsg_type = id;
|
||||||
|
req.gnl.cmd = NETDEV_CMD_DEV_GET;
|
||||||
|
req.gnl.version = 2;
|
||||||
|
|
||||||
|
err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex));
|
||||||
|
if (err < 0)
|
||||||
|
return libbpf_err(err);
|
||||||
|
|
||||||
|
err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
|
||||||
|
parse_xdp_features, NULL, &md);
|
||||||
|
if (err)
|
||||||
|
return libbpf_err(err);
|
||||||
|
|
||||||
|
opts->feature_flags = md.flags;
|
||||||
|
|
||||||
|
skip_feature_flags:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,7 +595,7 @@ static int tc_qdisc_modify(struct bpf_tc_hook *hook, int cmd, int flags)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
|
static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
|
||||||
@@ -587,12 +689,13 @@ static int get_tc_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
|||||||
|
|
||||||
static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
|
static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
|
||||||
{
|
{
|
||||||
struct bpf_prog_info info = {};
|
struct bpf_prog_info info;
|
||||||
__u32 info_len = sizeof(info);
|
__u32 info_len = sizeof(info);
|
||||||
char name[256];
|
char name[256];
|
||||||
int len, ret;
|
int len, ret;
|
||||||
|
|
||||||
ret = bpf_obj_get_info_by_fd(fd, &info, &info_len);
|
memset(&info, 0, info_len);
|
||||||
|
ret = bpf_prog_get_info_by_fd(fd, &info, &info_len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -672,7 +775,8 @@ int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
|||||||
|
|
||||||
info.opts = opts;
|
info.opts = opts;
|
||||||
|
|
||||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
|
||||||
|
&info);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return libbpf_err(ret);
|
return libbpf_err(ret);
|
||||||
if (!info.processed)
|
if (!info.processed)
|
||||||
@@ -738,7 +842,7 @@ static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||||
@@ -803,7 +907,8 @@ int bpf_tc_query(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
|||||||
|
|
||||||
info.opts = opts;
|
info.opts = opts;
|
||||||
|
|
||||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
|
||||||
|
&info);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return libbpf_err(ret);
|
return libbpf_err(ret);
|
||||||
if (!info.processed)
|
if (!info.processed)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
|
|||||||
|
|
||||||
static int nla_ok(const struct nlattr *nla, int remaining)
|
static int nla_ok(const struct nlattr *nla, int remaining)
|
||||||
{
|
{
|
||||||
return remaining >= sizeof(*nla) &&
|
return remaining >= (int)sizeof(*nla) &&
|
||||||
nla->nla_len >= sizeof(*nla) &&
|
nla->nla_len >= sizeof(*nla) &&
|
||||||
nla->nla_len <= remaining;
|
nla->nla_len <= remaining;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
|
|||||||
hlen += nlmsg_len(&err->msg);
|
hlen += nlmsg_len(&err->msg);
|
||||||
|
|
||||||
attr = (struct nlattr *) ((void *) err + hlen);
|
attr = (struct nlattr *) ((void *) err + hlen);
|
||||||
alen = nlh->nlmsg_len - hlen;
|
alen = (void *)nlh + nlh->nlmsg_len - (void *)attr;
|
||||||
|
|
||||||
if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
|
if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
|
||||||
extack_policy) != 0) {
|
extack_policy) != 0) {
|
||||||
|
|||||||
12
src/nlattr.h
@@ -14,6 +14,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <linux/genetlink.h>
|
||||||
|
|
||||||
/* avoid multiple definition of netlink features */
|
/* avoid multiple definition of netlink features */
|
||||||
#define __LINUX_NETLINK_H
|
#define __LINUX_NETLINK_H
|
||||||
@@ -58,6 +59,7 @@ struct libbpf_nla_req {
|
|||||||
union {
|
union {
|
||||||
struct ifinfomsg ifinfo;
|
struct ifinfomsg ifinfo;
|
||||||
struct tcmsg tc;
|
struct tcmsg tc;
|
||||||
|
struct genlmsghdr gnl;
|
||||||
};
|
};
|
||||||
char buf[128];
|
char buf[128];
|
||||||
};
|
};
|
||||||
@@ -89,11 +91,21 @@ static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
|
|||||||
return *(uint8_t *)libbpf_nla_data(nla);
|
return *(uint8_t *)libbpf_nla_data(nla);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla)
|
||||||
|
{
|
||||||
|
return *(uint16_t *)libbpf_nla_data(nla);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
|
static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
|
||||||
{
|
{
|
||||||
return *(uint32_t *)libbpf_nla_data(nla);
|
return *(uint32_t *)libbpf_nla_data(nla);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla)
|
||||||
|
{
|
||||||
|
return *(uint64_t *)libbpf_nla_data(nla);
|
||||||
|
}
|
||||||
|
|
||||||
static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
|
static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
|
||||||
{
|
{
|
||||||
return (const char *)libbpf_nla_data(nla);
|
return (const char *)libbpf_nla_data(nla);
|
||||||
|
|||||||
283
src/relo_core.c
@@ -95,6 +95,7 @@ static const char *core_relo_kind_str(enum bpf_core_relo_kind kind)
|
|||||||
case BPF_CORE_TYPE_ID_LOCAL: return "local_type_id";
|
case BPF_CORE_TYPE_ID_LOCAL: return "local_type_id";
|
||||||
case BPF_CORE_TYPE_ID_TARGET: return "target_type_id";
|
case BPF_CORE_TYPE_ID_TARGET: return "target_type_id";
|
||||||
case BPF_CORE_TYPE_EXISTS: return "type_exists";
|
case BPF_CORE_TYPE_EXISTS: return "type_exists";
|
||||||
|
case BPF_CORE_TYPE_MATCHES: return "type_matches";
|
||||||
case BPF_CORE_TYPE_SIZE: return "type_size";
|
case BPF_CORE_TYPE_SIZE: return "type_size";
|
||||||
case BPF_CORE_ENUMVAL_EXISTS: return "enumval_exists";
|
case BPF_CORE_ENUMVAL_EXISTS: return "enumval_exists";
|
||||||
case BPF_CORE_ENUMVAL_VALUE: return "enumval_value";
|
case BPF_CORE_ENUMVAL_VALUE: return "enumval_value";
|
||||||
@@ -123,6 +124,7 @@ static bool core_relo_is_type_based(enum bpf_core_relo_kind kind)
|
|||||||
case BPF_CORE_TYPE_ID_LOCAL:
|
case BPF_CORE_TYPE_ID_LOCAL:
|
||||||
case BPF_CORE_TYPE_ID_TARGET:
|
case BPF_CORE_TYPE_ID_TARGET:
|
||||||
case BPF_CORE_TYPE_EXISTS:
|
case BPF_CORE_TYPE_EXISTS:
|
||||||
|
case BPF_CORE_TYPE_MATCHES:
|
||||||
case BPF_CORE_TYPE_SIZE:
|
case BPF_CORE_TYPE_SIZE:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@@ -251,7 +253,7 @@ recur:
|
|||||||
* - field 'a' access (corresponds to '2' in low-level spec);
|
* - field 'a' access (corresponds to '2' in low-level spec);
|
||||||
* - array element #3 access (corresponds to '3' in low-level spec).
|
* - array element #3 access (corresponds to '3' in low-level spec).
|
||||||
*
|
*
|
||||||
* Type-based relocations (TYPE_EXISTS/TYPE_SIZE,
|
* Type-based relocations (TYPE_EXISTS/TYPE_MATCHES/TYPE_SIZE,
|
||||||
* TYPE_ID_LOCAL/TYPE_ID_TARGET) don't capture any field information. Their
|
* TYPE_ID_LOCAL/TYPE_ID_TARGET) don't capture any field information. Their
|
||||||
* spec and raw_spec are kept empty.
|
* spec and raw_spec are kept empty.
|
||||||
*
|
*
|
||||||
@@ -568,9 +570,14 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
|
|||||||
targ_spec->relo_kind = local_spec->relo_kind;
|
targ_spec->relo_kind = local_spec->relo_kind;
|
||||||
|
|
||||||
if (core_relo_is_type_based(local_spec->relo_kind)) {
|
if (core_relo_is_type_based(local_spec->relo_kind)) {
|
||||||
return bpf_core_types_are_compat(local_spec->btf,
|
if (local_spec->relo_kind == BPF_CORE_TYPE_MATCHES)
|
||||||
local_spec->root_type_id,
|
return bpf_core_types_match(local_spec->btf,
|
||||||
targ_btf, targ_id);
|
local_spec->root_type_id,
|
||||||
|
targ_btf, targ_id);
|
||||||
|
else
|
||||||
|
return bpf_core_types_are_compat(local_spec->btf,
|
||||||
|
local_spec->root_type_id,
|
||||||
|
targ_btf, targ_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
local_acc = &local_spec->spec[0];
|
local_acc = &local_spec->spec[0];
|
||||||
@@ -819,6 +826,7 @@ static int bpf_core_calc_type_relo(const struct bpf_core_relo *relo,
|
|||||||
*validate = false;
|
*validate = false;
|
||||||
break;
|
break;
|
||||||
case BPF_CORE_TYPE_EXISTS:
|
case BPF_CORE_TYPE_EXISTS:
|
||||||
|
case BPF_CORE_TYPE_MATCHES:
|
||||||
*val = 1;
|
*val = 1;
|
||||||
break;
|
break;
|
||||||
case BPF_CORE_TYPE_SIZE:
|
case BPF_CORE_TYPE_SIZE:
|
||||||
@@ -1410,3 +1418,270 @@ int bpf_core_calc_relo_insn(const char *prog_name,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bpf_core_names_match(const struct btf *local_btf, size_t local_name_off,
|
||||||
|
const struct btf *targ_btf, size_t targ_name_off)
|
||||||
|
{
|
||||||
|
const char *local_n, *targ_n;
|
||||||
|
size_t local_len, targ_len;
|
||||||
|
|
||||||
|
local_n = btf__name_by_offset(local_btf, local_name_off);
|
||||||
|
targ_n = btf__name_by_offset(targ_btf, targ_name_off);
|
||||||
|
|
||||||
|
if (str_is_empty(targ_n))
|
||||||
|
return str_is_empty(local_n);
|
||||||
|
|
||||||
|
targ_len = bpf_core_essential_name_len(targ_n);
|
||||||
|
local_len = bpf_core_essential_name_len(local_n);
|
||||||
|
|
||||||
|
return targ_len == local_len && strncmp(local_n, targ_n, local_len) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bpf_core_enums_match(const struct btf *local_btf, const struct btf_type *local_t,
|
||||||
|
const struct btf *targ_btf, const struct btf_type *targ_t)
|
||||||
|
{
|
||||||
|
__u16 local_vlen = btf_vlen(local_t);
|
||||||
|
__u16 targ_vlen = btf_vlen(targ_t);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (local_t->size != targ_t->size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (local_vlen > targ_vlen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* iterate over the local enum's variants and make sure each has
|
||||||
|
* a symbolic name correspondent in the target
|
||||||
|
*/
|
||||||
|
for (i = 0; i < local_vlen; i++) {
|
||||||
|
bool matched = false;
|
||||||
|
__u32 local_n_off, targ_n_off;
|
||||||
|
|
||||||
|
local_n_off = btf_is_enum(local_t) ? btf_enum(local_t)[i].name_off :
|
||||||
|
btf_enum64(local_t)[i].name_off;
|
||||||
|
|
||||||
|
for (j = 0; j < targ_vlen; j++) {
|
||||||
|
targ_n_off = btf_is_enum(targ_t) ? btf_enum(targ_t)[j].name_off :
|
||||||
|
btf_enum64(targ_t)[j].name_off;
|
||||||
|
|
||||||
|
if (bpf_core_names_match(local_btf, local_n_off, targ_btf, targ_n_off)) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bpf_core_composites_match(const struct btf *local_btf, const struct btf_type *local_t,
|
||||||
|
const struct btf *targ_btf, const struct btf_type *targ_t,
|
||||||
|
bool behind_ptr, int level)
|
||||||
|
{
|
||||||
|
const struct btf_member *local_m = btf_members(local_t);
|
||||||
|
__u16 local_vlen = btf_vlen(local_t);
|
||||||
|
__u16 targ_vlen = btf_vlen(targ_t);
|
||||||
|
int i, j, err;
|
||||||
|
|
||||||
|
if (local_vlen > targ_vlen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* check that all local members have a match in the target */
|
||||||
|
for (i = 0; i < local_vlen; i++, local_m++) {
|
||||||
|
const struct btf_member *targ_m = btf_members(targ_t);
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
for (j = 0; j < targ_vlen; j++, targ_m++) {
|
||||||
|
if (!bpf_core_names_match(local_btf, local_m->name_off,
|
||||||
|
targ_btf, targ_m->name_off))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = __bpf_core_types_match(local_btf, local_m->type, targ_btf,
|
||||||
|
targ_m->type, behind_ptr, level - 1);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
if (err > 0) {
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matched)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that two types "match". This function assumes that root types were
|
||||||
|
* already checked for name match.
|
||||||
|
*
|
||||||
|
* The matching relation is defined as follows:
|
||||||
|
* - modifiers and typedefs are stripped (and, hence, effectively ignored)
|
||||||
|
* - generally speaking types need to be of same kind (struct vs. struct, union
|
||||||
|
* vs. union, etc.)
|
||||||
|
* - exceptions are struct/union behind a pointer which could also match a
|
||||||
|
* forward declaration of a struct or union, respectively, and enum vs.
|
||||||
|
* enum64 (see below)
|
||||||
|
* Then, depending on type:
|
||||||
|
* - integers:
|
||||||
|
* - match if size and signedness match
|
||||||
|
* - arrays & pointers:
|
||||||
|
* - target types are recursively matched
|
||||||
|
* - structs & unions:
|
||||||
|
* - local members need to exist in target with the same name
|
||||||
|
* - for each member we recursively check match unless it is already behind a
|
||||||
|
* pointer, in which case we only check matching names and compatible kind
|
||||||
|
* - enums:
|
||||||
|
* - local variants have to have a match in target by symbolic name (but not
|
||||||
|
* numeric value)
|
||||||
|
* - size has to match (but enum may match enum64 and vice versa)
|
||||||
|
* - function pointers:
|
||||||
|
* - number and position of arguments in local type has to match target
|
||||||
|
* - for each argument and the return value we recursively check match
|
||||||
|
*/
|
||||||
|
int __bpf_core_types_match(const struct btf *local_btf, __u32 local_id, const struct btf *targ_btf,
|
||||||
|
__u32 targ_id, bool behind_ptr, int level)
|
||||||
|
{
|
||||||
|
const struct btf_type *local_t, *targ_t;
|
||||||
|
int depth = 32; /* max recursion depth */
|
||||||
|
__u16 local_k, targ_k;
|
||||||
|
|
||||||
|
if (level <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
recur:
|
||||||
|
depth--;
|
||||||
|
if (depth < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
local_t = skip_mods_and_typedefs(local_btf, local_id, &local_id);
|
||||||
|
targ_t = skip_mods_and_typedefs(targ_btf, targ_id, &targ_id);
|
||||||
|
if (!local_t || !targ_t)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* While the name check happens after typedefs are skipped, root-level
|
||||||
|
* typedefs would still be name-matched as that's the contract with
|
||||||
|
* callers.
|
||||||
|
*/
|
||||||
|
if (!bpf_core_names_match(local_btf, local_t->name_off, targ_btf, targ_t->name_off))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
local_k = btf_kind(local_t);
|
||||||
|
targ_k = btf_kind(targ_t);
|
||||||
|
|
||||||
|
switch (local_k) {
|
||||||
|
case BTF_KIND_UNKN:
|
||||||
|
return local_k == targ_k;
|
||||||
|
case BTF_KIND_FWD: {
|
||||||
|
bool local_f = BTF_INFO_KFLAG(local_t->info);
|
||||||
|
|
||||||
|
if (behind_ptr) {
|
||||||
|
if (local_k == targ_k)
|
||||||
|
return local_f == BTF_INFO_KFLAG(targ_t->info);
|
||||||
|
|
||||||
|
/* for forward declarations kflag dictates whether the
|
||||||
|
* target is a struct (0) or union (1)
|
||||||
|
*/
|
||||||
|
return (targ_k == BTF_KIND_STRUCT && !local_f) ||
|
||||||
|
(targ_k == BTF_KIND_UNION && local_f);
|
||||||
|
} else {
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* match if the forward declaration is for the same kind */
|
||||||
|
return local_f == BTF_INFO_KFLAG(targ_t->info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case BTF_KIND_ENUM:
|
||||||
|
case BTF_KIND_ENUM64:
|
||||||
|
if (!btf_is_any_enum(targ_t))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return bpf_core_enums_match(local_btf, local_t, targ_btf, targ_t);
|
||||||
|
case BTF_KIND_STRUCT:
|
||||||
|
case BTF_KIND_UNION:
|
||||||
|
if (behind_ptr) {
|
||||||
|
bool targ_f = BTF_INFO_KFLAG(targ_t->info);
|
||||||
|
|
||||||
|
if (local_k == targ_k)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (targ_k != BTF_KIND_FWD)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (local_k == BTF_KIND_UNION) == targ_f;
|
||||||
|
} else {
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return bpf_core_composites_match(local_btf, local_t, targ_btf, targ_t,
|
||||||
|
behind_ptr, level);
|
||||||
|
}
|
||||||
|
case BTF_KIND_INT: {
|
||||||
|
__u8 local_sgn;
|
||||||
|
__u8 targ_sgn;
|
||||||
|
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
local_sgn = btf_int_encoding(local_t) & BTF_INT_SIGNED;
|
||||||
|
targ_sgn = btf_int_encoding(targ_t) & BTF_INT_SIGNED;
|
||||||
|
|
||||||
|
return local_t->size == targ_t->size && local_sgn == targ_sgn;
|
||||||
|
}
|
||||||
|
case BTF_KIND_PTR:
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
behind_ptr = true;
|
||||||
|
|
||||||
|
local_id = local_t->type;
|
||||||
|
targ_id = targ_t->type;
|
||||||
|
goto recur;
|
||||||
|
case BTF_KIND_ARRAY: {
|
||||||
|
const struct btf_array *local_array = btf_array(local_t);
|
||||||
|
const struct btf_array *targ_array = btf_array(targ_t);
|
||||||
|
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (local_array->nelems != targ_array->nelems)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
local_id = local_array->type;
|
||||||
|
targ_id = targ_array->type;
|
||||||
|
goto recur;
|
||||||
|
}
|
||||||
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
|
struct btf_param *local_p = btf_params(local_t);
|
||||||
|
struct btf_param *targ_p = btf_params(targ_t);
|
||||||
|
__u16 local_vlen = btf_vlen(local_t);
|
||||||
|
__u16 targ_vlen = btf_vlen(targ_t);
|
||||||
|
int i, err;
|
||||||
|
|
||||||
|
if (local_k != targ_k)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (local_vlen != targ_vlen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < local_vlen; i++, local_p++, targ_p++) {
|
||||||
|
err = __bpf_core_types_match(local_btf, local_p->type, targ_btf,
|
||||||
|
targ_p->type, behind_ptr, level - 1);
|
||||||
|
if (err <= 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tail recurse for return type check */
|
||||||
|
local_id = local_t->type;
|
||||||
|
targ_id = targ_t->type;
|
||||||
|
goto recur;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pr_warn("unexpected kind %s relocated, local [%d], target [%d]\n",
|
||||||
|
btf_kind_str(local_t), local_id, targ_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ int __bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
|
|||||||
const struct btf *targ_btf, __u32 targ_id, int level);
|
const struct btf *targ_btf, __u32 targ_id, int level);
|
||||||
int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
|
int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
|
||||||
const struct btf *targ_btf, __u32 targ_id);
|
const struct btf *targ_btf, __u32 targ_id);
|
||||||
|
int __bpf_core_types_match(const struct btf *local_btf, __u32 local_id, const struct btf *targ_btf,
|
||||||
|
__u32 targ_id, bool behind_ptr, int level);
|
||||||
|
int bpf_core_types_match(const struct btf *local_btf, __u32 local_id, const struct btf *targ_btf,
|
||||||
|
__u32 targ_id);
|
||||||
|
|
||||||
size_t bpf_core_essential_name_len(const char *name);
|
size_t bpf_core_essential_name_len(const char *name);
|
||||||
|
|
||||||
|
|||||||
299
src/ringbuf.c
@@ -16,6 +16,7 @@
|
|||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
@@ -39,6 +40,23 @@ struct ring_buffer {
|
|||||||
int ring_cnt;
|
int ring_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct user_ring_buffer {
|
||||||
|
struct epoll_event event;
|
||||||
|
unsigned long *consumer_pos;
|
||||||
|
unsigned long *producer_pos;
|
||||||
|
void *data;
|
||||||
|
unsigned long mask;
|
||||||
|
size_t page_size;
|
||||||
|
int map_fd;
|
||||||
|
int epoll_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 8-byte ring buffer header structure */
|
||||||
|
struct ringbuf_hdr {
|
||||||
|
__u32 len;
|
||||||
|
__u32 pad;
|
||||||
|
};
|
||||||
|
|
||||||
static void ringbuf_unmap_ring(struct ring_buffer *rb, struct ring *r)
|
static void ringbuf_unmap_ring(struct ring_buffer *rb, struct ring *r)
|
||||||
{
|
{
|
||||||
if (r->consumer_pos) {
|
if (r->consumer_pos) {
|
||||||
@@ -59,12 +77,13 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
__u32 len = sizeof(info);
|
__u32 len = sizeof(info);
|
||||||
struct epoll_event *e;
|
struct epoll_event *e;
|
||||||
struct ring *r;
|
struct ring *r;
|
||||||
|
__u64 mmap_sz;
|
||||||
void *tmp;
|
void *tmp;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
err = bpf_obj_get_info_by_fd(map_fd, &info, &len);
|
err = bpf_map_get_info_by_fd(map_fd, &info, &len);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
||||||
@@ -97,8 +116,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
r->mask = info.max_entries - 1;
|
r->mask = info.max_entries - 1;
|
||||||
|
|
||||||
/* Map writable consumer page */
|
/* Map writable consumer page */
|
||||||
tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
|
||||||
map_fd, 0);
|
|
||||||
if (tmp == MAP_FAILED) {
|
if (tmp == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||||
@@ -110,9 +128,13 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
/* Map read-only producer page and data pages. We map twice as big
|
/* Map read-only producer page and data pages. We map twice as big
|
||||||
* data size to allow simple reading of samples that wrap around the
|
* data size to allow simple reading of samples that wrap around the
|
||||||
* end of a ring buffer. See kernel implementation for details.
|
* end of a ring buffer. See kernel implementation for details.
|
||||||
* */
|
*/
|
||||||
tmp = mmap(NULL, rb->page_size + 2 * info.max_entries, PROT_READ,
|
mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;
|
||||||
MAP_SHARED, map_fd, rb->page_size);
|
if (mmap_sz != (__u64)(size_t)mmap_sz) {
|
||||||
|
pr_warn("ringbuf: ring buffer size (%u) is too big\n", info.max_entries);
|
||||||
|
return libbpf_err(-E2BIG);
|
||||||
|
}
|
||||||
|
tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ, MAP_SHARED, map_fd, rb->page_size);
|
||||||
if (tmp == MAP_FAILED) {
|
if (tmp == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
ringbuf_unmap_ring(rb, r);
|
ringbuf_unmap_ring(rb, r);
|
||||||
@@ -202,7 +224,7 @@ static inline int roundup_len(__u32 len)
|
|||||||
return (len + 7) / 8 * 8;
|
return (len + 7) / 8 * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t ringbuf_process_ring(struct ring* r)
|
static int64_t ringbuf_process_ring(struct ring *r)
|
||||||
{
|
{
|
||||||
int *len_ptr, len, err;
|
int *len_ptr, len, err;
|
||||||
/* 64-bit to avoid overflow in case of extreme application behavior */
|
/* 64-bit to avoid overflow in case of extreme application behavior */
|
||||||
@@ -300,3 +322,266 @@ int ring_buffer__epoll_fd(const struct ring_buffer *rb)
|
|||||||
{
|
{
|
||||||
return rb->epoll_fd;
|
return rb->epoll_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void user_ringbuf_unmap_ring(struct user_ring_buffer *rb)
|
||||||
|
{
|
||||||
|
if (rb->consumer_pos) {
|
||||||
|
munmap(rb->consumer_pos, rb->page_size);
|
||||||
|
rb->consumer_pos = NULL;
|
||||||
|
}
|
||||||
|
if (rb->producer_pos) {
|
||||||
|
munmap(rb->producer_pos, rb->page_size + 2 * (rb->mask + 1));
|
||||||
|
rb->producer_pos = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_ring_buffer__free(struct user_ring_buffer *rb)
|
||||||
|
{
|
||||||
|
if (!rb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
user_ringbuf_unmap_ring(rb);
|
||||||
|
|
||||||
|
if (rb->epoll_fd >= 0)
|
||||||
|
close(rb->epoll_fd);
|
||||||
|
|
||||||
|
free(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
|
||||||
|
{
|
||||||
|
struct bpf_map_info info;
|
||||||
|
__u32 len = sizeof(info);
|
||||||
|
__u64 mmap_sz;
|
||||||
|
void *tmp;
|
||||||
|
struct epoll_event *rb_epoll;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
err = bpf_map_get_info_by_fd(map_fd, &info, &len);
|
||||||
|
if (err) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("user ringbuf: failed to get map info for fd=%d: %d\n", map_fd, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.type != BPF_MAP_TYPE_USER_RINGBUF) {
|
||||||
|
pr_warn("user ringbuf: map fd=%d is not BPF_MAP_TYPE_USER_RINGBUF\n", map_fd);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb->map_fd = map_fd;
|
||||||
|
rb->mask = info.max_entries - 1;
|
||||||
|
|
||||||
|
/* Map read-only consumer page */
|
||||||
|
tmp = mmap(NULL, rb->page_size, PROT_READ, MAP_SHARED, map_fd, 0);
|
||||||
|
if (tmp == MAP_FAILED) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("user ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||||
|
map_fd, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
rb->consumer_pos = tmp;
|
||||||
|
|
||||||
|
/* Map read-write the producer page and data pages. We map the data
|
||||||
|
* region as twice the total size of the ring buffer to allow the
|
||||||
|
* simple reading and writing of samples that wrap around the end of
|
||||||
|
* the buffer. See the kernel implementation for details.
|
||||||
|
*/
|
||||||
|
mmap_sz = rb->page_size + 2 * (__u64)info.max_entries;
|
||||||
|
if (mmap_sz != (__u64)(size_t)mmap_sz) {
|
||||||
|
pr_warn("user ringbuf: ring buf size (%u) is too big\n", info.max_entries);
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||||
|
map_fd, rb->page_size);
|
||||||
|
if (tmp == MAP_FAILED) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||||
|
map_fd, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb->producer_pos = tmp;
|
||||||
|
rb->data = tmp + rb->page_size;
|
||||||
|
|
||||||
|
rb_epoll = &rb->event;
|
||||||
|
rb_epoll->events = EPOLLOUT;
|
||||||
|
if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, rb_epoll) < 0) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("user ringbuf: failed to epoll add map fd=%d: %d\n", map_fd, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct user_ring_buffer *
|
||||||
|
user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts)
|
||||||
|
{
|
||||||
|
struct user_ring_buffer *rb;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, user_ring_buffer_opts))
|
||||||
|
return errno = EINVAL, NULL;
|
||||||
|
|
||||||
|
rb = calloc(1, sizeof(*rb));
|
||||||
|
if (!rb)
|
||||||
|
return errno = ENOMEM, NULL;
|
||||||
|
|
||||||
|
rb->page_size = getpagesize();
|
||||||
|
|
||||||
|
rb->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||||
|
if (rb->epoll_fd < 0) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("user ringbuf: failed to create epoll instance: %d\n", err);
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = user_ringbuf_map(rb, map_fd);
|
||||||
|
if (err)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
return rb;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
user_ring_buffer__free(rb);
|
||||||
|
return errno = -err, NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_ringbuf_commit(struct user_ring_buffer *rb, void *sample, bool discard)
|
||||||
|
{
|
||||||
|
__u32 new_len;
|
||||||
|
struct ringbuf_hdr *hdr;
|
||||||
|
uintptr_t hdr_offset;
|
||||||
|
|
||||||
|
hdr_offset = rb->mask + 1 + (sample - rb->data) - BPF_RINGBUF_HDR_SZ;
|
||||||
|
hdr = rb->data + (hdr_offset & rb->mask);
|
||||||
|
|
||||||
|
new_len = hdr->len & ~BPF_RINGBUF_BUSY_BIT;
|
||||||
|
if (discard)
|
||||||
|
new_len |= BPF_RINGBUF_DISCARD_BIT;
|
||||||
|
|
||||||
|
/* Synchronizes with smp_load_acquire() in __bpf_user_ringbuf_peek() in
|
||||||
|
* the kernel.
|
||||||
|
*/
|
||||||
|
__atomic_exchange_n(&hdr->len, new_len, __ATOMIC_ACQ_REL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_ring_buffer__discard(struct user_ring_buffer *rb, void *sample)
|
||||||
|
{
|
||||||
|
user_ringbuf_commit(rb, sample, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_ring_buffer__submit(struct user_ring_buffer *rb, void *sample)
|
||||||
|
{
|
||||||
|
user_ringbuf_commit(rb, sample, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *user_ring_buffer__reserve(struct user_ring_buffer *rb, __u32 size)
|
||||||
|
{
|
||||||
|
__u32 avail_size, total_size, max_size;
|
||||||
|
/* 64-bit to avoid overflow in case of extreme application behavior */
|
||||||
|
__u64 cons_pos, prod_pos;
|
||||||
|
struct ringbuf_hdr *hdr;
|
||||||
|
|
||||||
|
/* The top two bits are used as special flags */
|
||||||
|
if (size & (BPF_RINGBUF_BUSY_BIT | BPF_RINGBUF_DISCARD_BIT))
|
||||||
|
return errno = E2BIG, NULL;
|
||||||
|
|
||||||
|
/* Synchronizes with smp_store_release() in __bpf_user_ringbuf_peek() in
|
||||||
|
* the kernel.
|
||||||
|
*/
|
||||||
|
cons_pos = smp_load_acquire(rb->consumer_pos);
|
||||||
|
/* Synchronizes with smp_store_release() in user_ringbuf_commit() */
|
||||||
|
prod_pos = smp_load_acquire(rb->producer_pos);
|
||||||
|
|
||||||
|
max_size = rb->mask + 1;
|
||||||
|
avail_size = max_size - (prod_pos - cons_pos);
|
||||||
|
/* Round up total size to a multiple of 8. */
|
||||||
|
total_size = (size + BPF_RINGBUF_HDR_SZ + 7) / 8 * 8;
|
||||||
|
|
||||||
|
if (total_size > max_size)
|
||||||
|
return errno = E2BIG, NULL;
|
||||||
|
|
||||||
|
if (avail_size < total_size)
|
||||||
|
return errno = ENOSPC, NULL;
|
||||||
|
|
||||||
|
hdr = rb->data + (prod_pos & rb->mask);
|
||||||
|
hdr->len = size | BPF_RINGBUF_BUSY_BIT;
|
||||||
|
hdr->pad = 0;
|
||||||
|
|
||||||
|
/* Synchronizes with smp_load_acquire() in __bpf_user_ringbuf_peek() in
|
||||||
|
* the kernel.
|
||||||
|
*/
|
||||||
|
smp_store_release(rb->producer_pos, prod_pos + total_size);
|
||||||
|
|
||||||
|
return (void *)rb->data + ((prod_pos + BPF_RINGBUF_HDR_SZ) & rb->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __u64 ns_elapsed_timespec(const struct timespec *start, const struct timespec *end)
|
||||||
|
{
|
||||||
|
__u64 start_ns, end_ns, ns_per_s = 1000000000;
|
||||||
|
|
||||||
|
start_ns = (__u64)start->tv_sec * ns_per_s + start->tv_nsec;
|
||||||
|
end_ns = (__u64)end->tv_sec * ns_per_s + end->tv_nsec;
|
||||||
|
|
||||||
|
return end_ns - start_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *user_ring_buffer__reserve_blocking(struct user_ring_buffer *rb, __u32 size, int timeout_ms)
|
||||||
|
{
|
||||||
|
void *sample;
|
||||||
|
int err, ms_remaining = timeout_ms;
|
||||||
|
struct timespec start;
|
||||||
|
|
||||||
|
if (timeout_ms < 0 && timeout_ms != -1)
|
||||||
|
return errno = EINVAL, NULL;
|
||||||
|
|
||||||
|
if (timeout_ms != -1) {
|
||||||
|
err = clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
|
if (err)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
int cnt, ms_elapsed;
|
||||||
|
struct timespec curr;
|
||||||
|
__u64 ns_per_ms = 1000000;
|
||||||
|
|
||||||
|
sample = user_ring_buffer__reserve(rb, size);
|
||||||
|
if (sample)
|
||||||
|
return sample;
|
||||||
|
else if (errno != ENOSPC)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* The kernel guarantees at least one event notification
|
||||||
|
* delivery whenever at least one sample is drained from the
|
||||||
|
* ring buffer in an invocation to bpf_ringbuf_drain(). Other
|
||||||
|
* additional events may be delivered at any time, but only one
|
||||||
|
* event is guaranteed per bpf_ringbuf_drain() invocation,
|
||||||
|
* provided that a sample is drained, and the BPF program did
|
||||||
|
* not pass BPF_RB_NO_WAKEUP to bpf_ringbuf_drain(). If
|
||||||
|
* BPF_RB_FORCE_WAKEUP is passed to bpf_ringbuf_drain(), a
|
||||||
|
* wakeup event will be delivered even if no samples are
|
||||||
|
* drained.
|
||||||
|
*/
|
||||||
|
cnt = epoll_wait(rb->epoll_fd, &rb->event, 1, ms_remaining);
|
||||||
|
if (cnt < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (timeout_ms == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = clock_gettime(CLOCK_MONOTONIC, &curr);
|
||||||
|
if (err)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ms_elapsed = ns_elapsed_timespec(&start, &curr) / ns_per_ms;
|
||||||
|
ms_remaining = timeout_ms - ms_elapsed;
|
||||||
|
} while (ms_remaining > 0);
|
||||||
|
|
||||||
|
/* Try one more time to reserve a sample after the specified timeout has elapsed. */
|
||||||
|
return user_ring_buffer__reserve(rb, size);
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ struct bpf_load_and_run_opts {
|
|||||||
const char *errstr;
|
const char *errstr;
|
||||||
};
|
};
|
||||||
|
|
||||||
long bpf_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
|
long kern_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
|
||||||
|
|
||||||
static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
|
static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
{
|
{
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
return bpf_sys_bpf(cmd, attr, size);
|
return kern_sys_bpf(cmd, attr, size);
|
||||||
#else
|
#else
|
||||||
return syscall(__NR_bpf, cmd, attr, size);
|
return syscall(__NR_bpf, cmd, attr, size);
|
||||||
#endif
|
#endif
|
||||||
@@ -251,6 +251,29 @@ static inline int skel_map_update_elem(int fd, const void *key,
|
|||||||
return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
|
return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int skel_map_delete_elem(int fd, const void *key)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.map_fd = fd;
|
||||||
|
attr.key = (long)key;
|
||||||
|
|
||||||
|
return skel_sys_bpf(BPF_MAP_DELETE_ELEM, &attr, attr_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int skel_map_get_fd_by_id(__u32 id)
|
||||||
|
{
|
||||||
|
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_sz);
|
||||||
|
attr.map_id = id;
|
||||||
|
|
||||||
|
return skel_sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
|
static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
|
||||||
{
|
{
|
||||||
const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
|
const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
|
||||||
@@ -285,6 +308,8 @@ static inline int skel_link_create(int prog_fd, int target_fd,
|
|||||||
|
|
||||||
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
||||||
{
|
{
|
||||||
|
const size_t prog_load_attr_sz = offsetofend(union bpf_attr, fd_array);
|
||||||
|
const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
|
||||||
int map_fd = -1, prog_fd = -1, key = 0, err;
|
int map_fd = -1, prog_fd = -1, key = 0, err;
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
|
||||||
@@ -302,7 +327,7 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, prog_load_attr_sz);
|
||||||
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
|
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
|
||||||
attr.insns = (long) opts->insns;
|
attr.insns = (long) opts->insns;
|
||||||
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
|
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
|
||||||
@@ -313,18 +338,18 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
|||||||
attr.log_size = opts->ctx->log_size;
|
attr.log_size = opts->ctx->log_size;
|
||||||
attr.log_buf = opts->ctx->log_buf;
|
attr.log_buf = opts->ctx->log_buf;
|
||||||
attr.prog_flags = BPF_F_SLEEPABLE;
|
attr.prog_flags = BPF_F_SLEEPABLE;
|
||||||
err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, prog_load_attr_sz);
|
||||||
if (prog_fd < 0) {
|
if (prog_fd < 0) {
|
||||||
opts->errstr = "failed to load loader prog";
|
opts->errstr = "failed to load loader prog";
|
||||||
set_err;
|
set_err;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, test_run_attr_sz);
|
||||||
attr.test.prog_fd = prog_fd;
|
attr.test.prog_fd = prog_fd;
|
||||||
attr.test.ctx_in = (long) opts->ctx;
|
attr.test.ctx_in = (long) opts->ctx;
|
||||||
attr.test.ctx_size_in = opts->ctx->sz;
|
attr.test.ctx_size_in = opts->ctx->sz;
|
||||||
err = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));
|
err = skel_sys_bpf(BPF_PROG_RUN, &attr, test_run_attr_sz);
|
||||||
if (err < 0 || (int)attr.test.retval < 0) {
|
if (err < 0 || (int)attr.test.retval < 0) {
|
||||||
opts->errstr = "failed to execute loader prog";
|
opts->errstr = "failed to execute loader prog";
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|||||||
18
src/strset.c
@@ -19,19 +19,19 @@ struct strset {
|
|||||||
struct hashmap *strs_hash;
|
struct hashmap *strs_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t strset_hash_fn(const void *key, void *ctx)
|
static size_t strset_hash_fn(long key, void *ctx)
|
||||||
{
|
{
|
||||||
const struct strset *s = ctx;
|
const struct strset *s = ctx;
|
||||||
const char *str = s->strs_data + (long)key;
|
const char *str = s->strs_data + key;
|
||||||
|
|
||||||
return str_hash(str);
|
return str_hash(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool strset_equal_fn(const void *key1, const void *key2, void *ctx)
|
static bool strset_equal_fn(long key1, long key2, void *ctx)
|
||||||
{
|
{
|
||||||
const struct strset *s = ctx;
|
const struct strset *s = ctx;
|
||||||
const char *str1 = s->strs_data + (long)key1;
|
const char *str1 = s->strs_data + key1;
|
||||||
const char *str2 = s->strs_data + (long)key2;
|
const char *str2 = s->strs_data + key2;
|
||||||
|
|
||||||
return strcmp(str1, str2) == 0;
|
return strcmp(str1, str2) == 0;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ struct strset *strset__new(size_t max_data_sz, const char *init_data, size_t ini
|
|||||||
/* hashmap__add() returns EEXIST if string with the same
|
/* hashmap__add() returns EEXIST if string with the same
|
||||||
* content already is in the hash map
|
* content already is in the hash map
|
||||||
*/
|
*/
|
||||||
err = hashmap__add(hash, (void *)off, (void *)off);
|
err = hashmap__add(hash, off, off);
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
continue; /* duplicate */
|
continue; /* duplicate */
|
||||||
if (err)
|
if (err)
|
||||||
@@ -127,7 +127,7 @@ int strset__find_str(struct strset *set, const char *s)
|
|||||||
new_off = set->strs_data_len;
|
new_off = set->strs_data_len;
|
||||||
memcpy(p, s, len);
|
memcpy(p, s, len);
|
||||||
|
|
||||||
if (hashmap__find(set->strs_hash, (void *)new_off, (void **)&old_off))
|
if (hashmap__find(set->strs_hash, new_off, &old_off))
|
||||||
return old_off;
|
return old_off;
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
@@ -165,8 +165,8 @@ int strset__add_str(struct strset *set, const char *s)
|
|||||||
* contents doesn't exist already (HASHMAP_ADD strategy). If such
|
* contents doesn't exist already (HASHMAP_ADD strategy). If such
|
||||||
* string exists, we'll get its offset in old_off (that's old_key).
|
* string exists, we'll get its offset in old_off (that's old_key).
|
||||||
*/
|
*/
|
||||||
err = hashmap__insert(set->strs_hash, (void *)new_off, (void *)new_off,
|
err = hashmap__insert(set->strs_hash, new_off, new_off,
|
||||||
HASHMAP_ADD, (const void **)&old_off, NULL);
|
HASHMAP_ADD, &old_off, NULL);
|
||||||
if (err == -EEXIST)
|
if (err == -EEXIST)
|
||||||
return old_off; /* duplicated string, return existing offset */
|
return old_off; /* duplicated string, return existing offset */
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
#include <bpf/bpf_tracing.h>
|
#include <bpf/bpf_tracing.h>
|
||||||
#include <bpf/bpf_core_read.h>
|
|
||||||
|
|
||||||
/* Below types and maps are internal implementation details of libbpf's USDT
|
/* 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
|
* support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
|
||||||
@@ -30,14 +29,6 @@
|
|||||||
#ifndef BPF_USDT_MAX_IP_CNT
|
#ifndef BPF_USDT_MAX_IP_CNT
|
||||||
#define BPF_USDT_MAX_IP_CNT (4 * BPF_USDT_MAX_SPEC_CNT)
|
#define BPF_USDT_MAX_IP_CNT (4 * BPF_USDT_MAX_SPEC_CNT)
|
||||||
#endif
|
#endif
|
||||||
/* We use BPF CO-RE to detect support for BPF cookie from BPF side. This is
|
|
||||||
* the only dependency on CO-RE, so if it's undesirable, user can override
|
|
||||||
* BPF_USDT_HAS_BPF_COOKIE to specify whether to BPF cookie is supported or not.
|
|
||||||
*/
|
|
||||||
#ifndef BPF_USDT_HAS_BPF_COOKIE
|
|
||||||
#define BPF_USDT_HAS_BPF_COOKIE \
|
|
||||||
bpf_core_enum_value_exists(enum bpf_func_id___usdt, BPF_FUNC_get_attach_cookie___usdt)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum __bpf_usdt_arg_type {
|
enum __bpf_usdt_arg_type {
|
||||||
BPF_USDT_ARG_CONST,
|
BPF_USDT_ARG_CONST,
|
||||||
@@ -83,15 +74,12 @@ struct {
|
|||||||
__type(value, __u32);
|
__type(value, __u32);
|
||||||
} __bpf_usdt_ip_to_spec_id SEC(".maps") __weak;
|
} __bpf_usdt_ip_to_spec_id SEC(".maps") __weak;
|
||||||
|
|
||||||
/* don't rely on user's BPF code to have latest definition of bpf_func_id */
|
extern const _Bool LINUX_HAS_BPF_COOKIE __kconfig;
|
||||||
enum bpf_func_id___usdt {
|
|
||||||
BPF_FUNC_get_attach_cookie___usdt = 0xBAD, /* value doesn't matter */
|
|
||||||
};
|
|
||||||
|
|
||||||
static __always_inline
|
static __always_inline
|
||||||
int __bpf_usdt_spec_id(struct pt_regs *ctx)
|
int __bpf_usdt_spec_id(struct pt_regs *ctx)
|
||||||
{
|
{
|
||||||
if (!BPF_USDT_HAS_BPF_COOKIE) {
|
if (!LINUX_HAS_BPF_COOKIE) {
|
||||||
long ip = PT_REGS_IP(ctx);
|
long ip = PT_REGS_IP(ctx);
|
||||||
int *spec_id_ptr;
|
int *spec_id_ptr;
|
||||||
|
|
||||||
@@ -142,7 +130,10 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res)
|
|||||||
if (!spec)
|
if (!spec)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
if (arg_num >= BPF_USDT_MAX_ARG_CNT || arg_num >= spec->arg_cnt)
|
if (arg_num >= BPF_USDT_MAX_ARG_CNT)
|
||||||
|
return -ENOENT;
|
||||||
|
barrier_var(arg_num);
|
||||||
|
if (arg_num >= spec->arg_cnt)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
arg_spec = &spec->args[arg_num];
|
arg_spec = &spec->args[arg_num];
|
||||||
@@ -244,7 +235,7 @@ long bpf_usdt_cookie(struct pt_regs *ctx)
|
|||||||
*/
|
*/
|
||||||
#define BPF_USDT(name, args...) \
|
#define BPF_USDT(name, args...) \
|
||||||
name(struct pt_regs *ctx); \
|
name(struct pt_regs *ctx); \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args); \
|
____##name(struct pt_regs *ctx, ##args); \
|
||||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||||
{ \
|
{ \
|
||||||
@@ -253,7 +244,7 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
|||||||
return ____##name(___bpf_usdt_args(args)); \
|
return ____##name(___bpf_usdt_args(args)); \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
} \
|
} \
|
||||||
static __attribute__((always_inline)) typeof(name(0)) \
|
static __always_inline typeof(name(0)) \
|
||||||
____##name(struct pt_regs *ctx, ##args)
|
____##name(struct pt_regs *ctx, ##args)
|
||||||
|
|
||||||
#endif /* __USDT_BPF_H__ */
|
#endif /* __USDT_BPF_H__ */
|
||||||
|
|||||||
251
src/usdt.c
@@ -282,7 +282,7 @@ struct usdt_manager *usdt_manager_new(struct bpf_object *obj)
|
|||||||
* If this is not supported, USDTs with semaphores will not be supported.
|
* If this is not supported, USDTs with semaphores will not be supported.
|
||||||
* Added in: a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
* Added in: a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
||||||
*/
|
*/
|
||||||
man->has_sema_refcnt = access(ref_ctr_sysfs_path, F_OK) == 0;
|
man->has_sema_refcnt = faccessat(AT_FDCWD, ref_ctr_sysfs_path, F_OK, AT_EACCESS) == 0;
|
||||||
|
|
||||||
return man;
|
return man;
|
||||||
}
|
}
|
||||||
@@ -652,11 +652,9 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
|
|||||||
*
|
*
|
||||||
* [0] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
|
* [0] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
|
||||||
*/
|
*/
|
||||||
usdt_rel_ip = usdt_abs_ip = note.loc_addr;
|
usdt_abs_ip = note.loc_addr;
|
||||||
if (base_addr) {
|
if (base_addr)
|
||||||
usdt_abs_ip += base_addr - note.base_addr;
|
usdt_abs_ip += base_addr - note.base_addr;
|
||||||
usdt_rel_ip += base_addr - note.base_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When attaching uprobes (which is what USDTs basically are)
|
/* When attaching uprobes (which is what USDTs basically are)
|
||||||
* kernel expects file offset to be specified, not a relative
|
* kernel expects file offset to be specified, not a relative
|
||||||
@@ -875,31 +873,27 @@ static void bpf_link_usdt_dealloc(struct bpf_link *link)
|
|||||||
free(usdt_link);
|
free(usdt_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t specs_hash_fn(const void *key, void *ctx)
|
static size_t specs_hash_fn(long key, void *ctx)
|
||||||
{
|
{
|
||||||
const char *s = key;
|
return str_hash((char *)key);
|
||||||
|
|
||||||
return str_hash(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool specs_equal_fn(const void *key1, const void *key2, void *ctx)
|
static bool specs_equal_fn(long key1, long key2, void *ctx)
|
||||||
{
|
{
|
||||||
const char *s1 = key1;
|
return strcmp((char *)key1, (char *)key2) == 0;
|
||||||
const char *s2 = key2;
|
|
||||||
|
|
||||||
return strcmp(s1, s2) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash,
|
static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash,
|
||||||
struct bpf_link_usdt *link, struct usdt_target *target,
|
struct bpf_link_usdt *link, struct usdt_target *target,
|
||||||
int *spec_id, bool *is_new)
|
int *spec_id, bool *is_new)
|
||||||
{
|
{
|
||||||
void *tmp;
|
long tmp;
|
||||||
|
void *new_ids;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* check if we already allocated spec ID for this spec string */
|
/* check if we already allocated spec ID for this spec string */
|
||||||
if (hashmap__find(specs_hash, target->spec_str, &tmp)) {
|
if (hashmap__find(specs_hash, target->spec_str, &tmp)) {
|
||||||
*spec_id = (long)tmp;
|
*spec_id = tmp;
|
||||||
*is_new = false;
|
*is_new = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -907,17 +901,17 @@ static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash
|
|||||||
/* otherwise it's a new ID that needs to be set up in specs map and
|
/* otherwise it's a new ID that needs to be set up in specs map and
|
||||||
* returned back to usdt_manager when USDT link is detached
|
* returned back to usdt_manager when USDT link is detached
|
||||||
*/
|
*/
|
||||||
tmp = libbpf_reallocarray(link->spec_ids, link->spec_cnt + 1, sizeof(*link->spec_ids));
|
new_ids = libbpf_reallocarray(link->spec_ids, link->spec_cnt + 1, sizeof(*link->spec_ids));
|
||||||
if (!tmp)
|
if (!new_ids)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
link->spec_ids = tmp;
|
link->spec_ids = new_ids;
|
||||||
|
|
||||||
/* get next free spec ID, giving preference to free list, if not empty */
|
/* get next free spec ID, giving preference to free list, if not empty */
|
||||||
if (man->free_spec_cnt) {
|
if (man->free_spec_cnt) {
|
||||||
*spec_id = man->free_spec_ids[man->free_spec_cnt - 1];
|
*spec_id = man->free_spec_ids[man->free_spec_cnt - 1];
|
||||||
|
|
||||||
/* cache spec ID for current spec string for future lookups */
|
/* cache spec ID for current spec string for future lookups */
|
||||||
err = hashmap__add(specs_hash, target->spec_str, (void *)(long)*spec_id);
|
err = hashmap__add(specs_hash, target->spec_str, *spec_id);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -930,7 +924,7 @@ static int allocate_spec_id(struct usdt_manager *man, struct hashmap *specs_hash
|
|||||||
*spec_id = man->next_free_spec_id;
|
*spec_id = man->next_free_spec_id;
|
||||||
|
|
||||||
/* cache spec ID for current spec string for future lookups */
|
/* cache spec ID for current spec string for future lookups */
|
||||||
err = hashmap__add(specs_hash, target->spec_str, (void *)(long)*spec_id);
|
err = hashmap__add(specs_hash, target->spec_str, *spec_id);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -1147,12 +1141,13 @@ static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg);
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz);
|
||||||
|
|
||||||
static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note, __u64 usdt_cookie)
|
static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note, __u64 usdt_cookie)
|
||||||
{
|
{
|
||||||
|
struct usdt_arg_spec *arg;
|
||||||
const char *s;
|
const char *s;
|
||||||
int len;
|
int arg_sz, len;
|
||||||
|
|
||||||
spec->usdt_cookie = usdt_cookie;
|
spec->usdt_cookie = usdt_cookie;
|
||||||
spec->arg_cnt = 0;
|
spec->arg_cnt = 0;
|
||||||
@@ -1165,10 +1160,25 @@ static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note,
|
|||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = parse_usdt_arg(s, spec->arg_cnt, &spec->args[spec->arg_cnt]);
|
arg = &spec->args[spec->arg_cnt];
|
||||||
|
len = parse_usdt_arg(s, spec->arg_cnt, arg, &arg_sz);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
arg->arg_signed = arg_sz < 0;
|
||||||
|
if (arg_sz < 0)
|
||||||
|
arg_sz = -arg_sz;
|
||||||
|
|
||||||
|
switch (arg_sz) {
|
||||||
|
case 1: case 2: case 4: case 8:
|
||||||
|
arg->arg_bitshift = 64 - arg_sz * 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
|
||||||
|
spec->arg_cnt, s, arg_sz);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
s += len;
|
s += len;
|
||||||
spec->arg_cnt++;
|
spec->arg_cnt++;
|
||||||
}
|
}
|
||||||
@@ -1225,32 +1235,38 @@ static int calc_pt_regs_off(const char *reg_name)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
{
|
{
|
||||||
char *reg_name = NULL;
|
char reg_name[16];
|
||||||
int arg_sz, len, reg_off;
|
int len, reg_off;
|
||||||
long off;
|
long off;
|
||||||
|
|
||||||
if (sscanf(arg_str, " %d @ %ld ( %%%m[^)] ) %n", &arg_sz, &off, ®_name, &len) == 3) {
|
if (sscanf(arg_str, " %d @ %ld ( %%%15[^)] ) %n", arg_sz, &off, reg_name, &len) == 3) {
|
||||||
/* Memory dereference case, e.g., -4@-20(%rbp) */
|
/* Memory dereference case, e.g., -4@-20(%rbp) */
|
||||||
arg->arg_type = USDT_ARG_REG_DEREF;
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
} else if (sscanf(arg_str, " %d @ %%%ms %n", &arg_sz, ®_name, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ ( %%%15[^)] ) %n", arg_sz, reg_name, &len) == 2) {
|
||||||
|
/* Memory dereference case without offset, e.g., 8@(%rsp) */
|
||||||
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
|
arg->val_off = 0;
|
||||||
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
|
if (reg_off < 0)
|
||||||
|
return reg_off;
|
||||||
|
arg->reg_off = reg_off;
|
||||||
|
} else if (sscanf(arg_str, " %d @ %%%15s %n", arg_sz, reg_name, &len) == 2) {
|
||||||
/* Register read case, e.g., -4@%eax */
|
/* Register read case, e.g., -4@%eax */
|
||||||
arg->arg_type = USDT_ARG_REG;
|
arg->arg_type = USDT_ARG_REG;
|
||||||
arg->val_off = 0;
|
arg->val_off = 0;
|
||||||
|
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
} else if (sscanf(arg_str, " %d @ $%ld %n", &arg_sz, &off, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ $%ld %n", arg_sz, &off, &len) == 2) {
|
||||||
/* Constant value case, e.g., 4@$71 */
|
/* Constant value case, e.g., 4@$71 */
|
||||||
arg->arg_type = USDT_ARG_CONST;
|
arg->arg_type = USDT_ARG_CONST;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
@@ -1260,20 +1276,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->arg_signed = arg_sz < 0;
|
|
||||||
if (arg_sz < 0)
|
|
||||||
arg_sz = -arg_sz;
|
|
||||||
|
|
||||||
switch (arg_sz) {
|
|
||||||
case 1: case 2: case 4: case 8:
|
|
||||||
arg->arg_bitshift = 64 - arg_sz * 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
|
|
||||||
arg_num, arg_str, arg_sz);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1281,13 +1283,13 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
|
|
||||||
/* Do not support __s390__ for now, since user_pt_regs is broken with -m31. */
|
/* Do not support __s390__ for now, since user_pt_regs is broken with -m31. */
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
{
|
{
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
int arg_sz, len;
|
int len;
|
||||||
long off;
|
long off;
|
||||||
|
|
||||||
if (sscanf(arg_str, " %d @ %ld ( %%r%u ) %n", &arg_sz, &off, ®, &len) == 3) {
|
if (sscanf(arg_str, " %d @ %ld ( %%r%u ) %n", arg_sz, &off, ®, &len) == 3) {
|
||||||
/* Memory dereference case, e.g., -2@-28(%r15) */
|
/* Memory dereference case, e.g., -2@-28(%r15) */
|
||||||
arg->arg_type = USDT_ARG_REG_DEREF;
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
@@ -1296,7 +1298,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
|
arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
|
||||||
} else if (sscanf(arg_str, " %d @ %%r%u %n", &arg_sz, ®, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %%r%u %n", arg_sz, ®, &len) == 2) {
|
||||||
/* Register read case, e.g., -8@%r0 */
|
/* Register read case, e.g., -8@%r0 */
|
||||||
arg->arg_type = USDT_ARG_REG;
|
arg->arg_type = USDT_ARG_REG;
|
||||||
arg->val_off = 0;
|
arg->val_off = 0;
|
||||||
@@ -1305,7 +1307,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
|
arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
|
||||||
} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
|
||||||
/* Constant value case, e.g., 4@71 */
|
/* Constant value case, e.g., 4@71 */
|
||||||
arg->arg_type = USDT_ARG_CONST;
|
arg->arg_type = USDT_ARG_CONST;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
@@ -1315,20 +1317,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->arg_signed = arg_sz < 0;
|
|
||||||
if (arg_sz < 0)
|
|
||||||
arg_sz = -arg_sz;
|
|
||||||
|
|
||||||
switch (arg_sz) {
|
|
||||||
case 1: case 2: case 4: case 8:
|
|
||||||
arg->arg_bitshift = 64 - arg_sz * 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
|
|
||||||
arg_num, arg_str, arg_sz);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,41 +1336,38 @@ static int calc_pt_regs_off(const char *reg_name)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
{
|
{
|
||||||
char *reg_name = NULL;
|
char reg_name[16];
|
||||||
int arg_sz, len, reg_off;
|
int len, reg_off;
|
||||||
long off;
|
long off;
|
||||||
|
|
||||||
if (sscanf(arg_str, " %d @ \[ %m[a-z0-9], %ld ] %n", &arg_sz, ®_name, &off, &len) == 3) {
|
if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] , %ld ] %n", arg_sz, reg_name, &off, &len) == 3) {
|
||||||
/* Memory dereference case, e.g., -4@[sp, 96] */
|
/* Memory dereference case, e.g., -4@[sp, 96] */
|
||||||
arg->arg_type = USDT_ARG_REG_DEREF;
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
} else if (sscanf(arg_str, " %d @ \[ %m[a-z0-9] ] %n", &arg_sz, ®_name, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
|
||||||
/* Memory dereference case, e.g., -4@[sp] */
|
/* Memory dereference case, e.g., -4@[sp] */
|
||||||
arg->arg_type = USDT_ARG_REG_DEREF;
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
arg->val_off = 0;
|
arg->val_off = 0;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
|
||||||
/* Constant value case, e.g., 4@5 */
|
/* Constant value case, e.g., 4@5 */
|
||||||
arg->arg_type = USDT_ARG_CONST;
|
arg->arg_type = USDT_ARG_CONST;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
arg->reg_off = 0;
|
arg->reg_off = 0;
|
||||||
} else if (sscanf(arg_str, " %d @ %m[a-z0-9] %n", &arg_sz, ®_name, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
|
||||||
/* Register read case, e.g., -8@x4 */
|
/* Register read case, e.g., -8@x4 */
|
||||||
arg->arg_type = USDT_ARG_REG;
|
arg->arg_type = USDT_ARG_REG;
|
||||||
arg->val_off = 0;
|
arg->val_off = 0;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
@@ -1391,20 +1376,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->arg_signed = arg_sz < 0;
|
|
||||||
if (arg_sz < 0)
|
|
||||||
arg_sz = -arg_sz;
|
|
||||||
|
|
||||||
switch (arg_sz) {
|
|
||||||
case 1: case 2: case 4: case 8:
|
|
||||||
arg->arg_bitshift = 64 - arg_sz * 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
|
|
||||||
arg_num, arg_str, arg_sz);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1459,32 +1430,30 @@ static int calc_pt_regs_off(const char *reg_name)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
{
|
{
|
||||||
char *reg_name = NULL;
|
char reg_name[16];
|
||||||
int arg_sz, len, reg_off;
|
int len, reg_off;
|
||||||
long off;
|
long off;
|
||||||
|
|
||||||
if (sscanf(arg_str, " %d @ %ld ( %m[a-z0-9] ) %n", &arg_sz, &off, ®_name, &len) == 3) {
|
if (sscanf(arg_str, " %d @ %ld ( %15[a-z0-9] ) %n", arg_sz, &off, reg_name, &len) == 3) {
|
||||||
/* Memory dereference case, e.g., -8@-88(s0) */
|
/* Memory dereference case, e.g., -8@-88(s0) */
|
||||||
arg->arg_type = USDT_ARG_REG_DEREF;
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
|
||||||
/* Constant value case, e.g., 4@5 */
|
/* Constant value case, e.g., 4@5 */
|
||||||
arg->arg_type = USDT_ARG_CONST;
|
arg->arg_type = USDT_ARG_CONST;
|
||||||
arg->val_off = off;
|
arg->val_off = off;
|
||||||
arg->reg_off = 0;
|
arg->reg_off = 0;
|
||||||
} else if (sscanf(arg_str, " %d @ %m[a-z0-9] %n", &arg_sz, ®_name, &len) == 2) {
|
} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
|
||||||
/* Register read case, e.g., -8@a1 */
|
/* Register read case, e.g., -8@a1 */
|
||||||
arg->arg_type = USDT_ARG_REG;
|
arg->arg_type = USDT_ARG_REG;
|
||||||
arg->val_off = 0;
|
arg->val_off = 0;
|
||||||
reg_off = calc_pt_regs_off(reg_name);
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
free(reg_name);
|
|
||||||
if (reg_off < 0)
|
if (reg_off < 0)
|
||||||
return reg_off;
|
return reg_off;
|
||||||
arg->reg_off = reg_off;
|
arg->reg_off = reg_off;
|
||||||
@@ -1493,17 +1462,83 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->arg_signed = arg_sz < 0;
|
return len;
|
||||||
if (arg_sz < 0)
|
}
|
||||||
arg_sz = -arg_sz;
|
|
||||||
|
|
||||||
switch (arg_sz) {
|
#elif defined(__arm__)
|
||||||
case 1: case 2: case 4: case 8:
|
|
||||||
arg->arg_bitshift = 64 - arg_sz * 8;
|
static int calc_pt_regs_off(const char *reg_name)
|
||||||
break;
|
{
|
||||||
default:
|
static struct {
|
||||||
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
|
const char *name;
|
||||||
arg_num, arg_str, arg_sz);
|
size_t pt_regs_off;
|
||||||
|
} reg_map[] = {
|
||||||
|
{ "r0", offsetof(struct pt_regs, uregs[0]) },
|
||||||
|
{ "r1", offsetof(struct pt_regs, uregs[1]) },
|
||||||
|
{ "r2", offsetof(struct pt_regs, uregs[2]) },
|
||||||
|
{ "r3", offsetof(struct pt_regs, uregs[3]) },
|
||||||
|
{ "r4", offsetof(struct pt_regs, uregs[4]) },
|
||||||
|
{ "r5", offsetof(struct pt_regs, uregs[5]) },
|
||||||
|
{ "r6", offsetof(struct pt_regs, uregs[6]) },
|
||||||
|
{ "r7", offsetof(struct pt_regs, uregs[7]) },
|
||||||
|
{ "r8", offsetof(struct pt_regs, uregs[8]) },
|
||||||
|
{ "r9", offsetof(struct pt_regs, uregs[9]) },
|
||||||
|
{ "r10", offsetof(struct pt_regs, uregs[10]) },
|
||||||
|
{ "fp", offsetof(struct pt_regs, uregs[11]) },
|
||||||
|
{ "ip", offsetof(struct pt_regs, uregs[12]) },
|
||||||
|
{ "sp", offsetof(struct pt_regs, uregs[13]) },
|
||||||
|
{ "lr", offsetof(struct pt_regs, uregs[14]) },
|
||||||
|
{ "pc", offsetof(struct pt_regs, uregs[15]) },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
|
||||||
|
if (strcmp(reg_name, reg_map[i].name) == 0)
|
||||||
|
return reg_map[i].pt_regs_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_warn("usdt: unrecognized register '%s'\n", reg_name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
|
{
|
||||||
|
char reg_name[16];
|
||||||
|
int len, reg_off;
|
||||||
|
long off;
|
||||||
|
|
||||||
|
if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] , #%ld ] %n",
|
||||||
|
arg_sz, reg_name, &off, &len) == 3) {
|
||||||
|
/* Memory dereference case, e.g., -4@[fp, #96] */
|
||||||
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
|
arg->val_off = off;
|
||||||
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
|
if (reg_off < 0)
|
||||||
|
return reg_off;
|
||||||
|
arg->reg_off = reg_off;
|
||||||
|
} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
|
||||||
|
/* Memory dereference case, e.g., -4@[sp] */
|
||||||
|
arg->arg_type = USDT_ARG_REG_DEREF;
|
||||||
|
arg->val_off = 0;
|
||||||
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
|
if (reg_off < 0)
|
||||||
|
return reg_off;
|
||||||
|
arg->reg_off = reg_off;
|
||||||
|
} else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
|
||||||
|
/* Constant value case, e.g., 4@#5 */
|
||||||
|
arg->arg_type = USDT_ARG_CONST;
|
||||||
|
arg->val_off = off;
|
||||||
|
arg->reg_off = 0;
|
||||||
|
} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
|
||||||
|
/* Register read case, e.g., -8@r4 */
|
||||||
|
arg->arg_type = USDT_ARG_REG;
|
||||||
|
arg->val_off = 0;
|
||||||
|
reg_off = calc_pt_regs_off(reg_name);
|
||||||
|
if (reg_off < 0)
|
||||||
|
return reg_off;
|
||||||
|
arg->reg_off = reg_off;
|
||||||
|
} else {
|
||||||
|
pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1512,7 +1547,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
|
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
|
||||||
{
|
{
|
||||||
pr_warn("usdt: libbpf doesn't support USDTs on current architecture\n");
|
pr_warn("usdt: libbpf doesn't support USDTs on current architecture\n");
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|||||||
333
src/zip.c
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
/*
|
||||||
|
* Routines for dealing with .zip archives.
|
||||||
|
*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "libbpf_internal.h"
|
||||||
|
#include "zip.h"
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpacked"
|
||||||
|
#pragma GCC diagnostic ignored "-Wattributes"
|
||||||
|
|
||||||
|
/* Specification of ZIP file format can be found here:
|
||||||
|
* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
|
||||||
|
* For a high level overview of the structure of a ZIP file see
|
||||||
|
* sections 4.3.1 - 4.3.6.
|
||||||
|
*
|
||||||
|
* Data structures appearing in ZIP files do not contain any
|
||||||
|
* padding and they might be misaligned. To allow us to safely
|
||||||
|
* operate on pointers to such structures and their members, we
|
||||||
|
* declare the types as packed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define END_OF_CD_RECORD_MAGIC 0x06054b50
|
||||||
|
|
||||||
|
/* See section 4.3.16 of the spec. */
|
||||||
|
struct end_of_cd_record {
|
||||||
|
/* Magic value equal to END_OF_CD_RECORD_MAGIC */
|
||||||
|
__u32 magic;
|
||||||
|
|
||||||
|
/* Number of the file containing this structure or 0xFFFF if ZIP64 archive.
|
||||||
|
* Zip archive might span multiple files (disks).
|
||||||
|
*/
|
||||||
|
__u16 this_disk;
|
||||||
|
|
||||||
|
/* Number of the file containing the beginning of the central directory or
|
||||||
|
* 0xFFFF if ZIP64 archive.
|
||||||
|
*/
|
||||||
|
__u16 cd_disk;
|
||||||
|
|
||||||
|
/* Number of central directory records on this disk or 0xFFFF if ZIP64
|
||||||
|
* archive.
|
||||||
|
*/
|
||||||
|
__u16 cd_records;
|
||||||
|
|
||||||
|
/* Number of central directory records on all disks or 0xFFFF if ZIP64
|
||||||
|
* archive.
|
||||||
|
*/
|
||||||
|
__u16 cd_records_total;
|
||||||
|
|
||||||
|
/* Size of the central directory record or 0xFFFFFFFF if ZIP64 archive. */
|
||||||
|
__u32 cd_size;
|
||||||
|
|
||||||
|
/* Offset of the central directory from the beginning of the archive or
|
||||||
|
* 0xFFFFFFFF if ZIP64 archive.
|
||||||
|
*/
|
||||||
|
__u32 cd_offset;
|
||||||
|
|
||||||
|
/* Length of comment data following end of central directory record. */
|
||||||
|
__u16 comment_length;
|
||||||
|
|
||||||
|
/* Up to 64k of arbitrary bytes. */
|
||||||
|
/* uint8_t comment[comment_length] */
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define CD_FILE_HEADER_MAGIC 0x02014b50
|
||||||
|
#define FLAG_ENCRYPTED (1 << 0)
|
||||||
|
#define FLAG_HAS_DATA_DESCRIPTOR (1 << 3)
|
||||||
|
|
||||||
|
/* See section 4.3.12 of the spec. */
|
||||||
|
struct cd_file_header {
|
||||||
|
/* Magic value equal to CD_FILE_HEADER_MAGIC. */
|
||||||
|
__u32 magic;
|
||||||
|
__u16 version;
|
||||||
|
/* Minimum zip version needed to extract the file. */
|
||||||
|
__u16 min_version;
|
||||||
|
__u16 flags;
|
||||||
|
__u16 compression;
|
||||||
|
__u16 last_modified_time;
|
||||||
|
__u16 last_modified_date;
|
||||||
|
__u32 crc;
|
||||||
|
__u32 compressed_size;
|
||||||
|
__u32 uncompressed_size;
|
||||||
|
__u16 file_name_length;
|
||||||
|
__u16 extra_field_length;
|
||||||
|
__u16 file_comment_length;
|
||||||
|
/* Number of the disk where the file starts or 0xFFFF if ZIP64 archive. */
|
||||||
|
__u16 disk;
|
||||||
|
__u16 internal_attributes;
|
||||||
|
__u32 external_attributes;
|
||||||
|
/* Offset from the start of the disk containing the local file header to the
|
||||||
|
* start of the local file header.
|
||||||
|
*/
|
||||||
|
__u32 offset;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define LOCAL_FILE_HEADER_MAGIC 0x04034b50
|
||||||
|
|
||||||
|
/* See section 4.3.7 of the spec. */
|
||||||
|
struct local_file_header {
|
||||||
|
/* Magic value equal to LOCAL_FILE_HEADER_MAGIC. */
|
||||||
|
__u32 magic;
|
||||||
|
/* Minimum zip version needed to extract the file. */
|
||||||
|
__u16 min_version;
|
||||||
|
__u16 flags;
|
||||||
|
__u16 compression;
|
||||||
|
__u16 last_modified_time;
|
||||||
|
__u16 last_modified_date;
|
||||||
|
__u32 crc;
|
||||||
|
__u32 compressed_size;
|
||||||
|
__u32 uncompressed_size;
|
||||||
|
__u16 file_name_length;
|
||||||
|
__u16 extra_field_length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
struct zip_archive {
|
||||||
|
void *data;
|
||||||
|
__u32 size;
|
||||||
|
__u32 cd_offset;
|
||||||
|
__u32 cd_records;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *check_access(struct zip_archive *archive, __u32 offset, __u32 size)
|
||||||
|
{
|
||||||
|
if (offset + size > archive->size || offset > offset + size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return archive->data + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 on success, -EINVAL on error and -ENOTSUP if the eocd indicates the
|
||||||
|
* archive uses features which are not supported.
|
||||||
|
*/
|
||||||
|
static int try_parse_end_of_cd(struct zip_archive *archive, __u32 offset)
|
||||||
|
{
|
||||||
|
__u16 comment_length, cd_records;
|
||||||
|
struct end_of_cd_record *eocd;
|
||||||
|
__u32 cd_offset, cd_size;
|
||||||
|
|
||||||
|
eocd = check_access(archive, offset, sizeof(*eocd));
|
||||||
|
if (!eocd || eocd->magic != END_OF_CD_RECORD_MAGIC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
comment_length = eocd->comment_length;
|
||||||
|
if (offset + sizeof(*eocd) + comment_length != archive->size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cd_records = eocd->cd_records;
|
||||||
|
if (eocd->this_disk != 0 || eocd->cd_disk != 0 || eocd->cd_records_total != cd_records)
|
||||||
|
/* This is a valid eocd, but we only support single-file non-ZIP64 archives. */
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
cd_offset = eocd->cd_offset;
|
||||||
|
cd_size = eocd->cd_size;
|
||||||
|
if (!check_access(archive, cd_offset, cd_size))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
archive->cd_offset = cd_offset;
|
||||||
|
archive->cd_records = cd_records;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_cd(struct zip_archive *archive)
|
||||||
|
{
|
||||||
|
int64_t limit, offset;
|
||||||
|
int rc = -EINVAL;
|
||||||
|
|
||||||
|
if (archive->size <= sizeof(struct end_of_cd_record))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Because the end of central directory ends with a variable length array of
|
||||||
|
* up to 0xFFFF bytes we can't know exactly where it starts and need to
|
||||||
|
* search for it at the end of the file, scanning the (limit, offset] range.
|
||||||
|
*/
|
||||||
|
offset = archive->size - sizeof(struct end_of_cd_record);
|
||||||
|
limit = (int64_t)offset - (1 << 16);
|
||||||
|
|
||||||
|
for (; offset >= 0 && offset > limit && rc != 0; offset--) {
|
||||||
|
rc = try_parse_end_of_cd(archive, offset);
|
||||||
|
if (rc == -ENOTSUP)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct zip_archive *zip_archive_open(const char *path)
|
||||||
|
{
|
||||||
|
struct zip_archive *archive;
|
||||||
|
int err, fd;
|
||||||
|
off_t size;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return ERR_PTR(-errno);
|
||||||
|
|
||||||
|
size = lseek(fd, 0, SEEK_END);
|
||||||
|
if (size == (off_t)-1 || size > UINT32_MAX) {
|
||||||
|
close(fd);
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
err = -errno;
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (data == MAP_FAILED)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
archive = malloc(sizeof(*archive));
|
||||||
|
if (!archive) {
|
||||||
|
munmap(data, size);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
};
|
||||||
|
|
||||||
|
archive->data = data;
|
||||||
|
archive->size = size;
|
||||||
|
|
||||||
|
err = find_cd(archive);
|
||||||
|
if (err) {
|
||||||
|
munmap(data, size);
|
||||||
|
free(archive);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return archive;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zip_archive_close(struct zip_archive *archive)
|
||||||
|
{
|
||||||
|
munmap(archive->data, archive->size);
|
||||||
|
free(archive);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct local_file_header *local_file_header_at_offset(struct zip_archive *archive,
|
||||||
|
__u32 offset)
|
||||||
|
{
|
||||||
|
struct local_file_header *lfh;
|
||||||
|
|
||||||
|
lfh = check_access(archive, offset, sizeof(*lfh));
|
||||||
|
if (!lfh || lfh->magic != LOCAL_FILE_HEADER_MAGIC)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return lfh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_entry_at_offset(struct zip_archive *archive, __u32 offset, struct zip_entry *out)
|
||||||
|
{
|
||||||
|
struct local_file_header *lfh;
|
||||||
|
__u32 compressed_size;
|
||||||
|
const char *name;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
lfh = local_file_header_at_offset(archive, offset);
|
||||||
|
if (!lfh)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset += sizeof(*lfh);
|
||||||
|
if ((lfh->flags & FLAG_ENCRYPTED) || (lfh->flags & FLAG_HAS_DATA_DESCRIPTOR))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
name = check_access(archive, offset, lfh->file_name_length);
|
||||||
|
if (!name)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset += lfh->file_name_length;
|
||||||
|
if (!check_access(archive, offset, lfh->extra_field_length))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset += lfh->extra_field_length;
|
||||||
|
compressed_size = lfh->compressed_size;
|
||||||
|
data = check_access(archive, offset, compressed_size);
|
||||||
|
if (!data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
out->compression = lfh->compression;
|
||||||
|
out->name_length = lfh->file_name_length;
|
||||||
|
out->name = name;
|
||||||
|
out->data = data;
|
||||||
|
out->data_length = compressed_size;
|
||||||
|
out->data_offset = offset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zip_archive_find_entry(struct zip_archive *archive, const char *file_name,
|
||||||
|
struct zip_entry *out)
|
||||||
|
{
|
||||||
|
size_t file_name_length = strlen(file_name);
|
||||||
|
__u32 i, offset = archive->cd_offset;
|
||||||
|
|
||||||
|
for (i = 0; i < archive->cd_records; ++i) {
|
||||||
|
__u16 cdfh_name_length, cdfh_flags;
|
||||||
|
struct cd_file_header *cdfh;
|
||||||
|
const char *cdfh_name;
|
||||||
|
|
||||||
|
cdfh = check_access(archive, offset, sizeof(*cdfh));
|
||||||
|
if (!cdfh || cdfh->magic != CD_FILE_HEADER_MAGIC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
offset += sizeof(*cdfh);
|
||||||
|
cdfh_name_length = cdfh->file_name_length;
|
||||||
|
cdfh_name = check_access(archive, offset, cdfh_name_length);
|
||||||
|
if (!cdfh_name)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cdfh_flags = cdfh->flags;
|
||||||
|
if ((cdfh_flags & FLAG_ENCRYPTED) == 0 &&
|
||||||
|
(cdfh_flags & FLAG_HAS_DATA_DESCRIPTOR) == 0 &&
|
||||||
|
file_name_length == cdfh_name_length &&
|
||||||
|
memcmp(file_name, archive->data + offset, file_name_length) == 0) {
|
||||||
|
return get_entry_at_offset(archive, cdfh->offset, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += cdfh_name_length;
|
||||||
|
offset += cdfh->extra_field_length;
|
||||||
|
offset += cdfh->file_comment_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
47
src/zip.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
|
||||||
|
#ifndef __LIBBPF_ZIP_H
|
||||||
|
#define __LIBBPF_ZIP_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* Represents an open zip archive.
|
||||||
|
* Only basic ZIP files are supported, in particular the following are not
|
||||||
|
* supported:
|
||||||
|
* - encryption
|
||||||
|
* - streaming
|
||||||
|
* - multi-part ZIP files
|
||||||
|
* - ZIP64
|
||||||
|
*/
|
||||||
|
struct zip_archive;
|
||||||
|
|
||||||
|
/* Carries information on name, compression method, and data corresponding to a
|
||||||
|
* file in a zip archive.
|
||||||
|
*/
|
||||||
|
struct zip_entry {
|
||||||
|
/* Compression method as defined in pkzip spec. 0 means data is uncompressed. */
|
||||||
|
__u16 compression;
|
||||||
|
|
||||||
|
/* Non-null terminated name of the file. */
|
||||||
|
const char *name;
|
||||||
|
/* Length of the file name. */
|
||||||
|
__u16 name_length;
|
||||||
|
|
||||||
|
/* Pointer to the file data. */
|
||||||
|
const void *data;
|
||||||
|
/* Length of the file data. */
|
||||||
|
__u32 data_length;
|
||||||
|
/* Offset of the file data within the archive. */
|
||||||
|
__u32 data_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Open a zip archive. Returns NULL in case of an error. */
|
||||||
|
struct zip_archive *zip_archive_open(const char *path);
|
||||||
|
|
||||||
|
/* Close a zip archive and release resources. */
|
||||||
|
void zip_archive_close(struct zip_archive *archive);
|
||||||
|
|
||||||
|
/* Look up an entry corresponding to a file in given zip archive. */
|
||||||
|
int zip_archive_find_entry(struct zip_archive *archive, const char *name, struct zip_entry *out);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
|
||||||
To: bpf@vger.kernel.org
|
|
||||||
Cc: Alexei Starovoitov <ast@kernel.org>,
|
|
||||||
Daniel Borkmann <daniel@iogearbox.net>,
|
|
||||||
Andrii Nakryiko <andrii@kernel.org>
|
|
||||||
Subject: [PATCH bpf-next] selftests/bpf: Fix OOB write in test_verifier
|
|
||||||
Date: Tue, 14 Dec 2021 07:18:00 +0530 [thread overview]
|
|
||||||
Message-ID: <20211214014800.78762-1-memxor@gmail.com> (raw)
|
|
||||||
|
|
||||||
The commit referenced below added fixup_map_timer support (to create a
|
|
||||||
BPF map containing timers), but failed to increase the size of the
|
|
||||||
map_fds array, leading to out of bounds write. Fix this by changing
|
|
||||||
MAX_NR_MAPS to 22.
|
|
||||||
|
|
||||||
Fixes: e60e6962c503 ("selftests/bpf: Add tests for restricted helpers")
|
|
||||||
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
|
||||||
---
|
|
||||||
tools/testing/selftests/bpf/test_verifier.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
|
|
||||||
index ad5d30bafd93..33e2ecb3bef9 100644
|
|
||||||
--- a/tools/testing/selftests/bpf/test_verifier.c
|
|
||||||
+++ b/tools/testing/selftests/bpf/test_verifier.c
|
|
||||||
@@ -54,7 +54,7 @@
|
|
||||||
#define MAX_INSNS BPF_MAXINSNS
|
|
||||||
#define MAX_TEST_INSNS 1000000
|
|
||||||
#define MAX_FIXUPS 8
|
|
||||||
-#define MAX_NR_MAPS 21
|
|
||||||
+#define MAX_NR_MAPS 22
|
|
||||||
#define MAX_TEST_RUNS 8
|
|
||||||
#define POINTER_VALUE 0xcafe4all
|
|
||||||
#define TEST_DATA_LEN 64
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# This script is based on drgn script for generating Arch Linux bootstrap
|
|
||||||
# images.
|
|
||||||
# https://github.com/osandov/drgn/blob/master/scripts/vmtest/mkrootfs.sh
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
usage () {
|
|
||||||
USAGE_STRING="usage: $0 [NAME]
|
|
||||||
$0 -h
|
|
||||||
|
|
||||||
Build an Arch Linux root filesystem image for testing libbpf in a virtual
|
|
||||||
machine.
|
|
||||||
|
|
||||||
The image is generated as a zstd-compressed tarball.
|
|
||||||
|
|
||||||
This must be run as root, as most of the installation is done in a chroot.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
NAME name of generated image file (default:
|
|
||||||
libbpf-vmtest-rootfs-\$DATE.tar.zst)
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h display this help message and exit"
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
out)
|
|
||||||
echo "$USAGE_STRING"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
err)
|
|
||||||
echo "$USAGE_STRING" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
while getopts "h" OPT; do
|
|
||||||
case "$OPT" in
|
|
||||||
h)
|
|
||||||
usage out
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage err
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [[ $OPTIND -eq $# ]]; then
|
|
||||||
NAME="${!OPTIND}"
|
|
||||||
elif [[ $OPTIND -gt $# ]]; then
|
|
||||||
NAME="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
|
||||||
else
|
|
||||||
usage err
|
|
||||||
fi
|
|
||||||
|
|
||||||
pacman_conf=
|
|
||||||
root=
|
|
||||||
trap 'rm -rf "$pacman_conf" "$root"' EXIT
|
|
||||||
pacman_conf="$(mktemp -p "$PWD")"
|
|
||||||
cat > "$pacman_conf" << "EOF"
|
|
||||||
[options]
|
|
||||||
Architecture = x86_64
|
|
||||||
CheckSpace
|
|
||||||
SigLevel = Required DatabaseOptional
|
|
||||||
[core]
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
|
||||||
[extra]
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
|
||||||
[community]
|
|
||||||
Include = /etc/pacman.d/mirrorlist
|
|
||||||
EOF
|
|
||||||
root="$(mktemp -d -p "$PWD")"
|
|
||||||
|
|
||||||
packages=(
|
|
||||||
busybox
|
|
||||||
# libbpf dependencies.
|
|
||||||
libelf
|
|
||||||
zlib
|
|
||||||
# selftests test_progs dependencies.
|
|
||||||
binutils
|
|
||||||
elfutils
|
|
||||||
ethtool
|
|
||||||
glibc
|
|
||||||
iproute2
|
|
||||||
# selftests test_verifier dependencies.
|
|
||||||
libcap
|
|
||||||
)
|
|
||||||
|
|
||||||
pacstrap -C "$pacman_conf" -cGM "$root" "${packages[@]}"
|
|
||||||
|
|
||||||
# Remove unnecessary files from the chroot.
|
|
||||||
|
|
||||||
# We don't need the pacman databases anymore.
|
|
||||||
rm -rf "$root/var/lib/pacman/sync/"
|
|
||||||
# We don't need D, Fortran, or Go.
|
|
||||||
rm -f "$root/usr/lib/libgdruntime."* \
|
|
||||||
"$root/usr/lib/libgphobos."* \
|
|
||||||
"$root/usr/lib/libgfortran."* \
|
|
||||||
"$root/usr/lib/libgo."*
|
|
||||||
# We don't need any documentation.
|
|
||||||
rm -rf "$root/usr/share/{doc,help,man,texinfo}"
|
|
||||||
|
|
||||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
|
||||||
|
|
||||||
tar -C "$root" -c . | zstd -T0 -19 -o "$NAME"
|
|
||||||
chmod 644 "$NAME"
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This script builds a Debian root filesystem image for testing libbpf in a
|
|
||||||
# virtual machine. Requires debootstrap >= 1.0.95 and zstd.
|
|
||||||
|
|
||||||
# Use e.g. ./mkrootfs_debian.sh --arch=s390x to generate a rootfs for a
|
|
||||||
# foreign architecture. Requires configured binfmt_misc, e.g. using
|
|
||||||
# Debian/Ubuntu's qemu-user-binfmt package or
|
|
||||||
# https://github.com/multiarch/qemu-user-static.
|
|
||||||
|
|
||||||
set -e -u -x -o pipefail
|
|
||||||
|
|
||||||
# Check whether we are root now in order to avoid confusing errors later.
|
|
||||||
if [ "$(id -u)" != 0 ]; then
|
|
||||||
echo "$0 must run as root" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a working directory and schedule its deletion.
|
|
||||||
root=$(mktemp -d -p "$PWD")
|
|
||||||
trap 'rm -r "$root"' EXIT
|
|
||||||
|
|
||||||
# Install packages.
|
|
||||||
packages=(
|
|
||||||
binutils
|
|
||||||
busybox
|
|
||||||
elfutils
|
|
||||||
ethtool
|
|
||||||
iproute2
|
|
||||||
iptables
|
|
||||||
libcap2
|
|
||||||
libelf1
|
|
||||||
strace
|
|
||||||
zlib1g
|
|
||||||
)
|
|
||||||
packages=$(IFS=, && echo "${packages[*]}")
|
|
||||||
debootstrap --include="$packages" --variant=minbase "$@" bookworm "$root"
|
|
||||||
|
|
||||||
# Remove the init scripts (tests use their own). Also remove various
|
|
||||||
# unnecessary files in order to save space.
|
|
||||||
rm -rf \
|
|
||||||
"$root"/etc/rcS.d \
|
|
||||||
"$root"/usr/share/{doc,info,locale,man,zoneinfo} \
|
|
||||||
"$root"/var/cache/apt/archives/* \
|
|
||||||
"$root"/var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Apply common tweaks.
|
|
||||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
|
||||||
|
|
||||||
# Save the result.
|
|
||||||
name="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
|
||||||
rm -f "$name"
|
|
||||||
tar -C "$root" -c . | zstd -T0 -19 -o "$name"
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This script prepares a mounted root filesystem for testing libbpf in a virtual
|
|
||||||
# machine.
|
|
||||||
set -e -u -x -o pipefail
|
|
||||||
root=$1
|
|
||||||
shift
|
|
||||||
|
|
||||||
chroot "${root}" /bin/busybox --install
|
|
||||||
|
|
||||||
cat > "$root/etc/inittab" << "EOF"
|
|
||||||
::sysinit:/etc/init.d/rcS
|
|
||||||
::ctrlaltdel:/sbin/reboot
|
|
||||||
::shutdown:/sbin/swapoff -a
|
|
||||||
::shutdown:/bin/umount -a -r
|
|
||||||
::restart:/sbin/init
|
|
||||||
EOF
|
|
||||||
chmod 644 "$root/etc/inittab"
|
|
||||||
|
|
||||||
mkdir -m 755 -p "$root/etc/init.d" "$root/etc/rcS.d"
|
|
||||||
cat > "$root/etc/rcS.d/S10-mount" << "EOF"
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
/bin/mount proc /proc -t proc
|
|
||||||
|
|
||||||
# Mount devtmpfs if not mounted
|
|
||||||
if [[ -z $(/bin/mount -t devtmpfs) ]]; then
|
|
||||||
/bin/mount devtmpfs /dev -t devtmpfs
|
|
||||||
fi
|
|
||||||
|
|
||||||
/bin/mount sysfs /sys -t sysfs
|
|
||||||
/bin/mount bpffs /sys/fs/bpf -t bpf
|
|
||||||
/bin/mount debugfs /sys/kernel/debug -t debugfs
|
|
||||||
|
|
||||||
echo 'Listing currently mounted file systems'
|
|
||||||
/bin/mount
|
|
||||||
EOF
|
|
||||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
|
||||||
|
|
||||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
ip link set lo up
|
|
||||||
EOF
|
|
||||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
|
||||||
|
|
||||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
for path in /etc/rcS.d/S*; do
|
|
||||||
[ -x "$path" ] && "$path"
|
|
||||||
done
|
|
||||||
EOF
|
|
||||||
chmod 755 "$root/etc/init.d/rcS"
|
|
||||||
|
|
||||||
chmod 755 "$root"
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
# IBM Z self-hosted builder
|
|
||||||
|
|
||||||
libbpf CI uses an IBM-provided z15 self-hosted builder. There are no IBM Z
|
|
||||||
builds of GitHub (GH) Actions runner, and stable qemu-user has problems with .NET
|
|
||||||
apps, so the builder runs the x86_64 runner version with qemu-user built from
|
|
||||||
the master branch.
|
|
||||||
|
|
||||||
We are currently supporting runners for the following repositories:
|
|
||||||
* libbpf/libbpf
|
|
||||||
* kernel-patches/bpf
|
|
||||||
* kernel-patches/vmtest
|
|
||||||
|
|
||||||
Below instructions are directly applicable to libbpf, and require minor
|
|
||||||
modifications for kernel-patches repos. Currently, qemu-user-static Docker
|
|
||||||
image is shared between all GitHub runners, but separate actions-runner-\*
|
|
||||||
service / Docker image is created for each runner type.
|
|
||||||
|
|
||||||
## Configuring the builder.
|
|
||||||
|
|
||||||
### Install prerequisites.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo apt install -y docker.io # Ubuntu
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add services.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo cp *.service /etc/systemd/system/
|
|
||||||
$ sudo systemctl daemon-reload
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a config file.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo tee /etc/actions-runner-libbpf
|
|
||||||
repo=<owner>/<name>
|
|
||||||
access_token=<ghp_***>
|
|
||||||
```
|
|
||||||
|
|
||||||
Access token should have the repo scope, consult
|
|
||||||
https://docs.github.com/en/rest/reference/actions#create-a-registration-token-for-a-repository
|
|
||||||
for details.
|
|
||||||
|
|
||||||
### Autostart the x86_64 emulation support.
|
|
||||||
|
|
||||||
This step is important, you would not be able to build docker container
|
|
||||||
without having this service running. If container build fails, make sure
|
|
||||||
service is running properly.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo systemctl enable --now qemu-user-static
|
|
||||||
```
|
|
||||||
|
|
||||||
### Autostart the runner.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo systemctl enable --now actions-runner-libbpf
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rebuilding the image
|
|
||||||
|
|
||||||
In order to update the `iiilinuxibmcom/actions-runner-libbpf` image, e.g. to
|
|
||||||
get the latest OS security fixes, use the following commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo docker build \
|
|
||||||
--pull \
|
|
||||||
-f actions-runner-libbpf.Dockerfile \
|
|
||||||
-t iiilinuxibmcom/actions-runner-libbpf \
|
|
||||||
.
|
|
||||||
$ sudo systemctl restart actions-runner-libbpf
|
|
||||||
```
|
|
||||||
|
|
||||||
## Removing persistent data
|
|
||||||
|
|
||||||
The `actions-runner-libbpf` service stores various temporary data, such as
|
|
||||||
runner registration information, work directories and logs, in the
|
|
||||||
`actions-runner-libbpf` volume. In order to remove it and start from scratch,
|
|
||||||
e.g. when upgrading the runner or switching it to a different repository, use
|
|
||||||
the following commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo systemctl stop actions-runner-libbpf
|
|
||||||
$ sudo docker rm -f actions-runner-libbpf
|
|
||||||
$ sudo docker volume rm actions-runner-libbpf
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
In order to check if service is running, use the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo systemctl status <service name>
|
|
||||||
```
|
|
||||||
|
|
||||||
In order to get logs for service:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ journalctl -u <service name>
|
|
||||||
```
|
|
||||||
|
|
||||||
In order to check which containers are currently active:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo docker ps
|
|
||||||
```
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# Self-Hosted IBM Z Github Actions Runner.
|
|
||||||
|
|
||||||
# Temporary image: amd64 dependencies.
|
|
||||||
FROM amd64/ubuntu:20.04 as ld-prefix
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN apt-get update && apt-get -y install ca-certificates libicu66 libssl1.1
|
|
||||||
|
|
||||||
# Main image.
|
|
||||||
FROM s390x/ubuntu:20.04
|
|
||||||
|
|
||||||
# Packages for libbpf testing that are not installed by .github/actions/setup.
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN apt-get update && apt-get -y install \
|
|
||||||
bc \
|
|
||||||
bison \
|
|
||||||
cmake \
|
|
||||||
cpu-checker \
|
|
||||||
curl \
|
|
||||||
flex \
|
|
||||||
git \
|
|
||||||
jq \
|
|
||||||
linux-image-generic \
|
|
||||||
qemu-system-s390x \
|
|
||||||
rsync \
|
|
||||||
software-properties-common \
|
|
||||||
sudo \
|
|
||||||
tree
|
|
||||||
|
|
||||||
# amd64 dependencies.
|
|
||||||
COPY --from=ld-prefix / /usr/x86_64-linux-gnu/
|
|
||||||
RUN ln -fs ../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /usr/x86_64-linux-gnu/lib64/
|
|
||||||
RUN ln -fs /etc/resolv.conf /usr/x86_64-linux-gnu/etc/
|
|
||||||
ENV QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
|
||||||
|
|
||||||
# amd64 Github Actions Runner.
|
|
||||||
ARG version=2.285.0
|
|
||||||
RUN useradd -m actions-runner
|
|
||||||
RUN echo "actions-runner ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
|
||||||
RUN echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >>/etc/sudoers
|
|
||||||
RUN usermod -a -G kvm actions-runner
|
|
||||||
USER actions-runner
|
|
||||||
ENV USER=actions-runner
|
|
||||||
WORKDIR /home/actions-runner
|
|
||||||
RUN curl -L https://github.com/actions/runner/releases/download/v${version}/actions-runner-linux-x64-${version}.tar.gz | tar -xz
|
|
||||||
VOLUME /home/actions-runner
|
|
||||||
|
|
||||||
# Scripts.
|
|
||||||
COPY fs/ /
|
|
||||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
|
||||||
CMD ["/usr/bin/actions-runner"]
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Self-Hosted IBM Z Github Actions Runner
|
|
||||||
Wants=qemu-user-static
|
|
||||||
After=qemu-user-static
|
|
||||||
StartLimitIntervalSec=0
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
Restart=always
|
|
||||||
ExecStart=/usr/bin/docker run \
|
|
||||||
--device=/dev/kvm \
|
|
||||||
--env-file=/etc/actions-runner-libbpf \
|
|
||||||
--init \
|
|
||||||
--interactive \
|
|
||||||
--name=actions-runner-libbpf \
|
|
||||||
--rm \
|
|
||||||
--volume=actions-runner-libbpf:/home/actions-runner \
|
|
||||||
iiilinuxibmcom/actions-runner-libbpf
|
|
||||||
ExecStop=/bin/sh -c "docker exec actions-runner-libbpf kill -INT -- -1"
|
|
||||||
ExecStop=/bin/sh -c "docker wait actions-runner-libbpf"
|
|
||||||
ExecStop=/bin/sh -c "docker rm actions-runner-libbpf"
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#
|
|
||||||
# Ephemeral runner startup script.
|
|
||||||
#
|
|
||||||
# Expects the following environment variables:
|
|
||||||
#
|
|
||||||
# - repo=<owner>/<name>
|
|
||||||
# - access_token=<ghp_***>
|
|
||||||
#
|
|
||||||
|
|
||||||
set -e -u
|
|
||||||
|
|
||||||
# Check the cached registration token.
|
|
||||||
token_file=registration-token.json
|
|
||||||
set +e
|
|
||||||
expires_at=$(jq --raw-output .expires_at "$token_file" 2>/dev/null)
|
|
||||||
status=$?
|
|
||||||
set -e
|
|
||||||
if [[ $status -ne 0 || $(date +%s) -ge $(date -d "$expires_at" +%s) ]]; then
|
|
||||||
# Refresh the cached registration token.
|
|
||||||
curl \
|
|
||||||
-X POST \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-H "Authorization: token $access_token" \
|
|
||||||
"https://api.github.com/repos/$repo/actions/runners/registration-token" \
|
|
||||||
-o "$token_file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# (Re-)register the runner.
|
|
||||||
registration_token=$(jq --raw-output .token "$token_file")
|
|
||||||
./config.sh remove --token "$registration_token" || true
|
|
||||||
./config.sh \
|
|
||||||
--url "https://github.com/$repo" \
|
|
||||||
--token "$registration_token" \
|
|
||||||
--labels z15 \
|
|
||||||
--ephemeral
|
|
||||||
|
|
||||||
# Run one job.
|
|
||||||
./run.sh
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#
|
|
||||||
# Container entrypoint that waits for all spawned processes.
|
|
||||||
#
|
|
||||||
|
|
||||||
set -e -u
|
|
||||||
|
|
||||||
# /dev/kvm has host permissions, fix it.
|
|
||||||
if [ -e /dev/kvm ]; then
|
|
||||||
sudo chown root:kvm /dev/kvm
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a FIFO and start reading from its read end.
|
|
||||||
tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX")
|
|
||||||
trap 'rm -r "$tempdir"' EXIT
|
|
||||||
done="$tempdir/pipe"
|
|
||||||
mkfifo "$done"
|
|
||||||
cat "$done" & waiter=$!
|
|
||||||
|
|
||||||
# Start the workload. Its descendants will inherit the FIFO's write end.
|
|
||||||
status=0
|
|
||||||
if [ "$#" -eq 0 ]; then
|
|
||||||
bash 9>"$done" || status=$?
|
|
||||||
else
|
|
||||||
"$@" 9>"$done" || status=$?
|
|
||||||
fi
|
|
||||||
|
|
||||||
# When the workload and all of its descendants exit, the FIFO's write end will
|
|
||||||
# be closed and `cat "$done"` will exit. Wait until it happens. This is needed
|
|
||||||
# in order to handle SelfUpdater, which the workload may start in background
|
|
||||||
# before exiting.
|
|
||||||
wait "$waiter"
|
|
||||||
|
|
||||||
exit "$status"
|
|
||||||