mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-24 10:19:07 +08:00
Compare commits
248 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
583bddce6b | ||
|
|
a52fb86a96 | ||
|
|
e5dbc1a96f | ||
|
|
96333403ca | ||
|
|
928f2fc146 | ||
|
|
8fd8b5bb46 | ||
|
|
b999e8f2c1 | ||
|
|
c6c86a53f2 | ||
|
|
c69f0d12f3 | ||
|
|
033ad7ee78 | ||
|
|
397db2175d | ||
|
|
6756bdc96e | ||
|
|
9c1ae55dbd | ||
|
|
091f073ff0 | ||
|
|
ad51a528dc | ||
|
|
fa29cc01ff | ||
|
|
a2bec08412 | ||
|
|
080fd68e9c | ||
|
|
437f57042c | ||
|
|
f4f271b068 | ||
|
|
bd35a43bb3 | ||
|
|
d91f681d3b | ||
|
|
1e51491d05 | ||
|
|
37440e95d1 | ||
|
|
681f2f9291 | ||
|
|
0e4638ec14 | ||
|
|
234a45a128 | ||
|
|
8687395198 | ||
|
|
0cccc9ff28 | ||
|
|
b50eb28758 | ||
|
|
8d936a1570 | ||
|
|
2c8602eb54 | ||
|
|
1ef23426e7 | ||
|
|
d2100072b9 | ||
|
|
f3edca46e5 | ||
|
|
cabb077325 | ||
|
|
b95b281039 | ||
|
|
5033d7177e | ||
|
|
49058f8c6f | ||
|
|
8b20ffa4b9 | ||
|
|
1b1e30679f | ||
|
|
e7a82fc033 | ||
|
|
7c5583ab2d | ||
|
|
0d9d85e345 | ||
|
|
c8c4edf4c9 | ||
|
|
23983fd75b | ||
|
|
4bbdefdce1 | ||
|
|
5bc09e54fa | ||
|
|
9f61b5b95c | ||
|
|
baa3268b13 | ||
|
|
f5599ef856 | ||
|
|
99c65fed78 | ||
|
|
e9adfa851f | ||
|
|
8363b8d4e6 | ||
|
|
f892b464d0 | ||
|
|
a4132d1590 | ||
|
|
303916a126 | ||
|
|
8eea7ed8e8 | ||
|
|
fa030ffd20 | ||
|
|
ea06bc30fa | ||
|
|
531ac0e65f | ||
|
|
e35cb347ce | ||
|
|
68fa3f0b57 | ||
|
|
1c145f0fda | ||
|
|
418c07226a | ||
|
|
5ec0ba6530 | ||
|
|
600ba1c5e1 | ||
|
|
aa73e35dc3 | ||
|
|
dca6176410 | ||
|
|
6f88f26945 | ||
|
|
f7af143516 | ||
|
|
4f3c7b3e13 | ||
|
|
b85e83f6cb | ||
|
|
33d1fbea57 | ||
|
|
b234d12c97 | ||
|
|
7a1d185108 | ||
|
|
76d5bb6a13 | ||
|
|
c42bfcbf0e | ||
|
|
c2fc7c15a3 | ||
|
|
4060a65222 | ||
|
|
a26f6b1375 | ||
|
|
6e686c26fa | ||
|
|
ab067ed371 | ||
|
|
9b69fbe4d1 | ||
|
|
04d8fc50ab | ||
|
|
ceff1e0363 | ||
|
|
d28acc595f | ||
|
|
9ef191ea7d | ||
|
|
1add860402 | ||
|
|
c658f21738 | ||
|
|
9f519af7f4 | ||
|
|
b7bdc604ef | ||
|
|
354dd9844e | ||
|
|
9b91dce691 | ||
|
|
83535cb2bf | ||
|
|
3f05b513d4 | ||
|
|
0d0d05de08 | ||
|
|
44409068f7 | ||
|
|
16ecc53e73 | ||
|
|
38f66776db | ||
|
|
e9d33df74d | ||
|
|
05b515de7d | ||
|
|
c2bbeaa900 | ||
|
|
799d153f41 | ||
|
|
69ff3960eb | ||
|
|
b91f53ec5f | ||
|
|
dd8f1bdd45 | ||
|
|
3720f31852 | ||
|
|
c51c492a65 | ||
|
|
d3e68e036e | ||
|
|
6ce8910d4d | ||
|
|
79b1d813f9 | ||
|
|
26954e103d | ||
|
|
c8c02fca3a | ||
|
|
0e2f5f9615 | ||
|
|
b539321838 | ||
|
|
0f15f88443 | ||
|
|
bada95a5f3 | ||
|
|
fb929625dc | ||
|
|
1a828b3d58 | ||
|
|
330f4683e2 | ||
|
|
2ef7f5607c | ||
|
|
4da243c179 | ||
|
|
4d8fc6d438 | ||
|
|
6d4abdda08 | ||
|
|
67ab4c0f82 | ||
|
|
df45cf7a3e | ||
|
|
4438972ccc | ||
|
|
09cd9ff2db | ||
|
|
e7d860d2fc | ||
|
|
ff3d2702d8 | ||
|
|
44f9712f79 | ||
|
|
fe4cb796df | ||
|
|
15de8ad80d | ||
|
|
d7a137510a | ||
|
|
91e4f27dd7 | ||
|
|
1339ef70a3 | ||
|
|
c204e3d610 | ||
|
|
32d0a03332 | ||
|
|
05346cfd90 | ||
|
|
a7a32b899c | ||
|
|
68a051f2d2 | ||
|
|
8e80367637 | ||
|
|
9a5adecc62 | ||
|
|
b923d0e3c6 | ||
|
|
f02e248ae1 | ||
|
|
e152510d72 | ||
|
|
59ac1946b0 | ||
|
|
5150a4a0fb | ||
|
|
2a25957df6 | ||
|
|
e441f55089 | ||
|
|
beb9f88080 | ||
|
|
c7b5116f71 | ||
|
|
2b0cd55bf5 | ||
|
|
188276ca5f | ||
|
|
87c4984da8 | ||
|
|
a5611ba6e8 | ||
|
|
c6e01425b6 | ||
|
|
58e3a8fac1 | ||
|
|
1b27702c14 | ||
|
|
39cf9fc90f | ||
|
|
bc4a6e9709 | ||
|
|
4a50ceb043 | ||
|
|
4d86cae4f0 | ||
|
|
33b374395f | ||
|
|
ade4409352 | ||
|
|
2f9abb2a26 | ||
|
|
fca60960ea | ||
|
|
0db22b01a1 | ||
|
|
807b9d7be1 | ||
|
|
a3d02f9ab4 | ||
|
|
54aac21f7e | ||
|
|
d8dd0beb98 | ||
|
|
e94f57a9ab | ||
|
|
bda436be4a | ||
|
|
a30df5c09f | ||
|
|
e776bf7ec7 | ||
|
|
46688687d5 | ||
|
|
19cbbd8f52 | ||
|
|
c87b3a6065 | ||
|
|
4c55ba2b19 | ||
|
|
104006a054 | ||
|
|
bf83a95dee | ||
|
|
732f598282 | ||
|
|
de3c5a17cb | ||
|
|
1a8a75037b | ||
|
|
1a26b51b1c | ||
|
|
2cc0829775 | ||
|
|
92cb475558 | ||
|
|
8b2782a1f2 | ||
|
|
886e8149a0 | ||
|
|
d275397111 | ||
|
|
ede18f80d8 | ||
|
|
07cd489681 | ||
|
|
d2f307c7f6 | ||
|
|
990cef2a0c | ||
|
|
4c2c521513 | ||
|
|
b1e911e9ba | ||
|
|
ae673dc91f | ||
|
|
5a256d12bf | ||
|
|
ae8edc7624 | ||
|
|
8f8b4a14fa | ||
|
|
476e158b07 | ||
|
|
13e1ee420e | ||
|
|
3e2bab6d2c | ||
|
|
9084f4cd4d | ||
|
|
66d20edaf0 | ||
|
|
d8d6772ab8 | ||
|
|
4397d09cd8 | ||
|
|
5771dacd3d | ||
|
|
d34efeeef1 | ||
|
|
db63a5aa5d | ||
|
|
d60f568961 | ||
|
|
e78a36f4b0 | ||
|
|
c8a7eb06bd | ||
|
|
b48c14807b | ||
|
|
a3b4055ec7 | ||
|
|
30603852f4 | ||
|
|
1a28fa5dac | ||
|
|
def5576b37 | ||
|
|
3e45a16621 | ||
|
|
2c0e53cb08 | ||
|
|
6227c6f8dd | ||
|
|
00ad180d07 | ||
|
|
715a58d593 | ||
|
|
11052fc1be | ||
|
|
97ecda3b25 | ||
|
|
342bcfa319 | ||
|
|
c020432531 | ||
|
|
99ce275b52 | ||
|
|
c0a5f7ee11 | ||
|
|
0da9ba439f | ||
|
|
c4735d9e05 | ||
|
|
563f1d3fff | ||
|
|
c5d4295fc5 | ||
|
|
b606dc725e | ||
|
|
f615047aa0 | ||
|
|
84a508a51f | ||
|
|
c59016e100 | ||
|
|
509ef92905 | ||
|
|
2c9394f2a3 | ||
|
|
0f4d83f3ab | ||
|
|
6a7b28b6a1 | ||
|
|
d76d264ac0 | ||
|
|
63a3bdf23a | ||
|
|
12fa15e89a | ||
|
|
b987dcfecb | ||
|
|
9c1ab4d070 |
14
.lgtm.yml
Normal file
14
.lgtm.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 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
|
||||||
137
.travis.yml
137
.travis.yml
@@ -1,13 +1,64 @@
|
|||||||
sudo: required
|
sudo: required
|
||||||
dist: xenial
|
language: bash
|
||||||
|
dist: bionic
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
|
- PROJECT_NAME='libbpf'
|
||||||
|
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
|
||||||
- CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
|
- CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
|
||||||
|
- VMTEST_ROOT="$TRAVIS_BUILD_DIR/travis-ci/vmtest"
|
||||||
- REPO_ROOT="$TRAVIS_BUILD_DIR"
|
- REPO_ROOT="$TRAVIS_BUILD_DIR"
|
||||||
|
- GIT_FETCH_DEPTH=64
|
||||||
|
- VMTEST_SETUPCMD="PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
|
||||||
|
jobs:
|
||||||
|
# Setup command override.
|
||||||
|
# 5.5.0-rc6 is built from bpf-next; TODO(hex@): remove when pahole v1.16 is available
|
||||||
|
- KERNEL=5.5.0-rc6
|
||||||
|
- KERNEL=5.5.0
|
||||||
|
- KERNEL=LATEST
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- qemu-kvm
|
||||||
|
- zstd
|
||||||
|
- binutils-dev
|
||||||
|
- elfutils
|
||||||
|
- libcap-dev
|
||||||
|
- libelf-dev
|
||||||
|
install: sudo adduser "${USER}" kvm
|
||||||
|
before_script:
|
||||||
|
- wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
- echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main" | sudo tee -a /etc/apt/sources.list
|
||||||
|
- echo "deb http://archive.ubuntu.com/ubuntu eoan main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
|
||||||
|
- sudo apt-get -qq update
|
||||||
|
- sudo apt-get -y install dwarves=1.15-1
|
||||||
|
- sudo apt-get -qq -y install clang-10 lld-10 llvm-10
|
||||||
|
- if [[ "${KERNEL}" = 'LATEST' ]]; then ${VMTEST_ROOT}/build_latest_kernel.sh travis-ci/vmtest/bpf-next; fi
|
||||||
|
- ${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
|
||||||
|
# Escape whitespace characters.
|
||||||
|
- setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
||||||
|
- if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||||
|
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||||
|
else
|
||||||
|
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||||
|
fi; exitstatus=$?
|
||||||
|
- test $exitstatus -le 1
|
||||||
|
script:
|
||||||
|
- test $exitstatus -eq 0
|
||||||
|
|
||||||
|
stages:
|
||||||
|
# Run Coverity periodically instead of for each PR for following reasons:
|
||||||
|
# 1) Coverity jobs are heavily rate-limited
|
||||||
|
# 2) Due to security restrictions of encrypted environment variables
|
||||||
|
# in Travis CI, pull requests made from forks can't access encrypted
|
||||||
|
# env variables, making Coverity unusable
|
||||||
|
# See: https://docs.travis-ci.com/user/pull-requests#pull-requests-and-security-restrictions
|
||||||
|
- name: Coverity
|
||||||
|
if: type = cron
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
@@ -22,10 +73,10 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
# Override before_script: so VMTEST before_install commands are not executed.
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
@@ -39,10 +90,9 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN_ASAN || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN_ASAN
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
@@ -56,10 +106,9 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN_CLANG || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN_CLANG
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
@@ -73,10 +122,9 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN_CLANG_ASAN || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN_CLANG_ASAN
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
@@ -90,10 +138,9 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN_GCC8 || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN_GCC8
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
@@ -107,16 +154,58 @@ jobs:
|
|||||||
- docker --version
|
- docker --version
|
||||||
install:
|
install:
|
||||||
- $CI_MANAGERS/debian.sh SETUP
|
- $CI_MANAGERS/debian.sh SETUP
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- $CI_MANAGERS/debian.sh RUN_GCC8_ASAN || travis_terminate
|
||||||
- $CI_MANAGERS/debian.sh RUN_GCC8_ASAN
|
|
||||||
- set +e
|
|
||||||
after_script:
|
after_script:
|
||||||
- $CI_MANAGERS/debian.sh CLEANUP
|
- $CI_MANAGERS/debian.sh CLEANUP
|
||||||
|
|
||||||
- name: Ubuntu Xenial
|
- name: Ubuntu Bionic
|
||||||
language: bash
|
language: bash
|
||||||
|
before_script: true
|
||||||
script:
|
script:
|
||||||
- set -e
|
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||||
- sudo $CI_MANAGERS/xenial.sh
|
|
||||||
- set +e
|
- name: Ubuntu Bionic (arm)
|
||||||
|
arch: arm64
|
||||||
|
language: bash
|
||||||
|
before_script: true
|
||||||
|
script:
|
||||||
|
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||||
|
|
||||||
|
- name: Ubuntu Bionic (s390x)
|
||||||
|
arch: s390x
|
||||||
|
language: bash
|
||||||
|
before_script: true
|
||||||
|
script:
|
||||||
|
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||||
|
|
||||||
|
- name: Ubuntu Bionic (ppc64le)
|
||||||
|
arch: ppc64le
|
||||||
|
language: bash
|
||||||
|
before_script: true
|
||||||
|
script:
|
||||||
|
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||||
|
|
||||||
|
- stage: Coverity
|
||||||
|
language: bash
|
||||||
|
env:
|
||||||
|
# Coverity configuration
|
||||||
|
# COVERITY_SCAN_TOKEN=xxx
|
||||||
|
# Encrypted using `travis encrypt --repo libbpf/libbpf COVERITY_SCAN_TOKEN=xxx`
|
||||||
|
- secure: "I9OsMRHbb82IUivDp+I+w/jEQFOJgBDAqYqf1ollqCM1QhocxMcS9bwIAgfPhdXi2hohV7sRrVMZstahY67FAvJLGxNopi4tAPDIAaIFxgO0yDxMhaTMx5xDfMwlIm2FOP/9gB9BQsd6M7CmoQZgXYwBIv7xd1ooxoQrh2rOK1YrRl7UQu3+c3zPTjDfIYZzR3bFttMqZ9/c4U0v8Ry5IFXrel3hCshndHA1TtttJrUSrILlZcmVc1ch7JIy6zCbCU/2lGv0B/7rWXfF8MT7O9jPtFOhJ1DEcd2zhw2n4j9YT3a8OhtnM61LA6ask632mwCOsxpFLTun7AzuR1Cb5mdPHsxhxnCHcXXARa2mJjem0QG1NhwxwJE8sbRDapojexxCvweYlEN40ofwMDSnj/qNt95XIcrk0tiIhGFx0gVNWvAdmZwx+N4mwGPMTAN0AEOFjpgI+ZdB89m+tL/CbEgE1flc8QxUxJhcp5OhH6yR0z9qYOp0nXIbHsIaCiRvt/7LqFRQfheifztWVz4mdQlCdKS9gcOQ09oKicPevKO1L0Ue3cb7Ug7jOpMs+cdh3XokJtUeYEr1NijMHT9+CTAhhO5RToWXIZRon719z3fwoUBNDREATwVFMlVxqSO/pbYgaKminigYbl785S89YYaZ6E5UvaKRHM6KHKMDszs="
|
||||||
|
- COVERITY_SCAN_PROJECT_NAME="libbpf"
|
||||||
|
- COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
||||||
|
- COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
|
||||||
|
# Note: `make -C src/` as a BUILD_COMMAND will not work here
|
||||||
|
- COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd src/"
|
||||||
|
- COVERITY_SCAN_BUILD_COMMAND="make"
|
||||||
|
install:
|
||||||
|
- sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' >>/etc/apt/sources.list
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get -y build-dep libelf-dev
|
||||||
|
- sudo apt-get install -y libelf-dev pkg-config
|
||||||
|
# Override before_script: so VMTEST before_script commands are not executed.
|
||||||
|
before_script: true
|
||||||
|
script:
|
||||||
|
- scripts/coverity.sh || travis_terminate
|
||||||
|
|||||||
1
BPF-CHECKPOINT-COMMIT
Normal file
1
BPF-CHECKPOINT-COMMIT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
08dc225d8868d5094ada62f471ebdfcce9dbc298
|
||||||
@@ -1 +1 @@
|
|||||||
66b5f1c439843bcbab01cc7f3854ae2742f3d1e3
|
35b9211c0a2427e8f39e534f442f43804fc8d5ca
|
||||||
|
|||||||
32
LICENSE.BSD-2-Clause
Normal file
32
LICENSE.BSD-2-Clause
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Valid-License-Identifier: BSD-2-Clause
|
||||||
|
SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
|
||||||
|
Usage-Guide:
|
||||||
|
To use the BSD 2-clause "Simplified" License put the following SPDX
|
||||||
|
tag/value pair into a comment according to the placement guidelines in
|
||||||
|
the licensing rules documentation:
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
License-Text:
|
||||||
|
|
||||||
|
Copyright (c) <year> <owner> . All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
503
LICENSE.LPGL-2.1
Normal file
503
LICENSE.LPGL-2.1
Normal file
@@ -0,0 +1,503 @@
|
|||||||
|
Valid-License-Identifier: LGPL-2.1
|
||||||
|
Valid-License-Identifier: LGPL-2.1+
|
||||||
|
SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html
|
||||||
|
Usage-Guide:
|
||||||
|
To use this license in source code, put one of the following SPDX
|
||||||
|
tag/value pairs into a comment according to the placement
|
||||||
|
guidelines in the licensing rules documentation.
|
||||||
|
For 'GNU Lesser General Public License (LGPL) version 2.1 only' use:
|
||||||
|
SPDX-License-Identifier: LGPL-2.1
|
||||||
|
For 'GNU Lesser General Public License (LGPL) version 2.1 or any later
|
||||||
|
version' use:
|
||||||
|
SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
License-Text:
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts as
|
||||||
|
the successor of the GNU Library Public License, version 2, hence the
|
||||||
|
version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your freedom to
|
||||||
|
share and change it. By contrast, the GNU General Public Licenses are
|
||||||
|
intended to guarantee your freedom to share and change free software--to
|
||||||
|
make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some specially
|
||||||
|
designated software packages--typically libraries--of the Free Software
|
||||||
|
Foundation and other authors who decide to use it. You can use it too, but
|
||||||
|
we suggest you first think carefully about whether this license or the
|
||||||
|
ordinary General Public License is the better strategy to use in any
|
||||||
|
particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you have
|
||||||
|
the freedom to distribute copies of free software (and charge for this
|
||||||
|
service if you wish); that you receive source code or can get it if you
|
||||||
|
want it; that you can change the software and use pieces of it in new free
|
||||||
|
programs; and that you are informed that you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for you if
|
||||||
|
you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis or for
|
||||||
|
a fee, you must give the recipients all the rights that we gave you. You
|
||||||
|
must make sure that they, too, receive or can get the source code. If you
|
||||||
|
link other code with the library, you must provide complete object files to
|
||||||
|
the recipients, so that they can relink them with the library after making
|
||||||
|
changes to the library and recompiling it. And you must show them these
|
||||||
|
terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that there is no
|
||||||
|
warranty for the free library. Also, if the library is modified by someone
|
||||||
|
else and passed on, the recipients should know that what they have is not
|
||||||
|
the original version, so that the original author's reputation will not be
|
||||||
|
affected by problems that might be introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of any
|
||||||
|
free program. We wish to make sure that a company cannot effectively
|
||||||
|
restrict the users of a free program by obtaining a restrictive license
|
||||||
|
from a patent holder. Therefore, we insist that any patent license obtained
|
||||||
|
for a version of the library must be consistent with the full freedom of
|
||||||
|
use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the ordinary GNU
|
||||||
|
General Public License. This license, the GNU Lesser General Public
|
||||||
|
License, applies to certain designated libraries, and is quite different
|
||||||
|
from the ordinary General Public License. We use this license for certain
|
||||||
|
libraries in order to permit linking those libraries into non-free
|
||||||
|
programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using a
|
||||||
|
shared library, the combination of the two is legally speaking a combined
|
||||||
|
work, a derivative of the original library. The ordinary General Public
|
||||||
|
License therefore permits such linking only if the entire combination fits
|
||||||
|
its criteria of freedom. The Lesser General Public License permits more lax
|
||||||
|
criteria for linking other code with the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it does
|
||||||
|
Less to protect the user's freedom than the ordinary General Public
|
||||||
|
License. It also provides other free software developers Less of an
|
||||||
|
advantage over competing non-free programs. These disadvantages are the
|
||||||
|
reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to encourage
|
||||||
|
the widest possible use of a certain library, so that it becomes a de-facto
|
||||||
|
standard. To achieve this, non-free programs must be allowed to use the
|
||||||
|
library. A more frequent case is that a free library does the same job as
|
||||||
|
widely used non-free libraries. In this case, there is little to gain by
|
||||||
|
limiting the free library to free software only, so we use the Lesser
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free programs
|
||||||
|
enables a greater number of people to use a large body of free
|
||||||
|
software. For example, permission to use the GNU C Library in non-free
|
||||||
|
programs enables many more people to use the whole GNU operating system, as
|
||||||
|
well as its variant, the GNU/Linux operating system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the users'
|
||||||
|
freedom, it does ensure that the user of a program that is linked with the
|
||||||
|
Library has the freedom and the wherewithal to run that program using a
|
||||||
|
modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification
|
||||||
|
follow. Pay close attention to the difference between a "work based on the
|
||||||
|
library" and a "work that uses the library". The former contains code
|
||||||
|
derived from the library, whereas the latter must be combined with the
|
||||||
|
library in order to run.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other program
|
||||||
|
which contains a notice placed by the copyright holder or other
|
||||||
|
authorized party saying it may be distributed under the terms of this
|
||||||
|
Lesser General Public License (also called "this License"). Each
|
||||||
|
licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work which
|
||||||
|
has been distributed under these terms. A "work based on the Library"
|
||||||
|
means either the Library or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Library or a portion of it, either
|
||||||
|
verbatim or with modifications and/or translated straightforwardly into
|
||||||
|
another language. (Hereinafter, translation is included without
|
||||||
|
limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for making
|
||||||
|
modifications to it. For a library, complete source code means all the
|
||||||
|
source code for all modules it contains, plus any associated interface
|
||||||
|
definition files, plus the scripts used to control compilation and
|
||||||
|
installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of running
|
||||||
|
a program using the Library is not restricted, and output from such a
|
||||||
|
program is covered only if its contents constitute a work based on the
|
||||||
|
Library (independent of the use of the Library in a tool for writing
|
||||||
|
it). Whether that is true depends on what the Library does and what the
|
||||||
|
program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's complete
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the notices
|
||||||
|
that refer to this License and to the absence of any warranty; and
|
||||||
|
distribute a copy of this License along with the Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion of it,
|
||||||
|
thus forming a work based on the Library, and copy and distribute such
|
||||||
|
modifications or work under the terms of Section 1 above, provided that
|
||||||
|
you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices stating
|
||||||
|
that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no charge to
|
||||||
|
all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a table
|
||||||
|
of data to be supplied by an application program that uses the
|
||||||
|
facility, other than as an argument passed when the facility is
|
||||||
|
invoked, then you must make a good faith effort to ensure that, in
|
||||||
|
the event an application does not supply such function or table, the
|
||||||
|
facility still operates, and performs whatever part of its purpose
|
||||||
|
remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has a
|
||||||
|
purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must be
|
||||||
|
optional: if the application does not supply it, the square root
|
||||||
|
function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library, and
|
||||||
|
can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based on
|
||||||
|
the Library, the distribution of the whole must be on the terms of this
|
||||||
|
License, whose permissions for other licensees extend to the entire
|
||||||
|
whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of a
|
||||||
|
storage or distribution medium does not bring the other work under the
|
||||||
|
scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so that
|
||||||
|
they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in these
|
||||||
|
notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for that
|
||||||
|
copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of the
|
||||||
|
Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or derivative of
|
||||||
|
it, under Section 2) in object code or executable form under the terms
|
||||||
|
of Sections 1 and 2 above provided that you accompany it with the
|
||||||
|
complete corresponding machine-readable source code, which must be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy from a
|
||||||
|
designated place, then offering equivalent access to copy the source
|
||||||
|
code from the same place satisfies the requirement to distribute the
|
||||||
|
source code, even though third parties are not compelled to copy the
|
||||||
|
source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the Library, but
|
||||||
|
is designed to work with the Library by being compiled or linked with
|
||||||
|
it, is called a "work that uses the Library". Such a work, in isolation,
|
||||||
|
is not a derivative work of the Library, and therefore falls outside the
|
||||||
|
scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library creates
|
||||||
|
an executable that is a derivative of the Library (because it contains
|
||||||
|
portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License. Section 6
|
||||||
|
states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is
|
||||||
|
not. Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data structure
|
||||||
|
layouts and accessors, and small macros and small inline functions (ten
|
||||||
|
lines or less in length), then the use of the object file is
|
||||||
|
unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section
|
||||||
|
6. Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or link a
|
||||||
|
"work that uses the Library" with the Library to produce a work
|
||||||
|
containing portions of the Library, and distribute that work under terms
|
||||||
|
of your choice, provided that the terms permit modification of the work
|
||||||
|
for the customer's own use and reverse engineering for debugging such
|
||||||
|
modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work during
|
||||||
|
execution displays copyright notices, you must include the copyright
|
||||||
|
notice for the Library among them, as well as a reference directing the
|
||||||
|
user to the copy of this License. Also, you must do one of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding machine-readable
|
||||||
|
source code for the Library including whatever changes were used in
|
||||||
|
the work (which must be distributed under Sections 1 and 2 above);
|
||||||
|
and, if the work is an executable linked with the Library, with the
|
||||||
|
complete machine-readable "work that uses the Library", as object
|
||||||
|
code and/or source code, so that the user can modify the Library and
|
||||||
|
then relink to produce a modified executable containing the modified
|
||||||
|
Library. (It is understood that the user who changes the contents of
|
||||||
|
definitions files in the Library will not necessarily be able to
|
||||||
|
recompile the application to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a copy
|
||||||
|
of the library already present on the user's computer system, rather
|
||||||
|
than copying library functions into the executable, and (2) will
|
||||||
|
operate properly with a modified version of the library, if the user
|
||||||
|
installs one, as long as the modified version is interface-compatible
|
||||||
|
with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at least three
|
||||||
|
years, to give the same user the materials specified in Subsection
|
||||||
|
6a, above, for a charge no more than the cost of performing this
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy from a
|
||||||
|
designated place, offer equivalent access to copy the above specified
|
||||||
|
materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these materials
|
||||||
|
or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the Library"
|
||||||
|
must include any data and utility programs needed for reproducing the
|
||||||
|
executable from it. However, as a special exception, the materials to be
|
||||||
|
distributed need not include anything that is normally distributed (in
|
||||||
|
either source or binary form) with the major components (compiler,
|
||||||
|
kernel, and so on) of the operating system on which the executable runs,
|
||||||
|
unless that component itself accompanies the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license restrictions
|
||||||
|
of other proprietary libraries that do not normally accompany the
|
||||||
|
operating system. Such a contradiction means you cannot use both them
|
||||||
|
and the Library together in an executable that you distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the Library
|
||||||
|
side-by-side in a single library together with other library facilities
|
||||||
|
not covered by this License, and distribute such a combined library,
|
||||||
|
provided that the separate distribution of the work based on the Library
|
||||||
|
and of the other library facilities is otherwise permitted, and provided
|
||||||
|
that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based on
|
||||||
|
the Library, uncombined with any other library facilities. This must
|
||||||
|
be distributed under the terms of the Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact that part
|
||||||
|
of it is a work based on the Library, and explaining where to find
|
||||||
|
the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute the
|
||||||
|
Library except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense, link with, or distribute the
|
||||||
|
Library is void, and will automatically terminate your rights under this
|
||||||
|
License. However, parties who have received copies, or rights, from you
|
||||||
|
under this License will not have their licenses terminated so long as
|
||||||
|
such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not signed
|
||||||
|
it. However, nothing else grants you permission to modify or distribute
|
||||||
|
the Library or its derivative works. These actions are prohibited by law
|
||||||
|
if you do not accept this License. Therefore, by modifying or
|
||||||
|
distributing the Library (or any work based on the Library), you
|
||||||
|
indicate your acceptance of this License to do so, and all its terms and
|
||||||
|
conditions for copying, distributing or modifying the Library or works
|
||||||
|
based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted
|
||||||
|
herein. You are not responsible for enforcing compliance by third
|
||||||
|
parties with this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent license
|
||||||
|
would not permit royalty-free redistribution of the Library by all
|
||||||
|
those who receive copies directly or indirectly through you, then the
|
||||||
|
only way you could satisfy both it and this License would be to refrain
|
||||||
|
entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply, and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is implemented
|
||||||
|
by public license practices. Many people have made generous
|
||||||
|
contributions to the wide range of software distributed through that
|
||||||
|
system in reliance on consistent application of that system; it is up
|
||||||
|
to the author/donor to decide if he or she is willing to distribute
|
||||||
|
software through any other system and a licensee cannot impose that
|
||||||
|
choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in certain
|
||||||
|
countries either by patents or by copyrighted interfaces, the original
|
||||||
|
copyright holder who places the Library under this License may add an
|
||||||
|
explicit geographical distribution limitation excluding those
|
||||||
|
countries, so that distribution is permitted only in or among countries
|
||||||
|
not thus excluded. In such case, this License incorporates the
|
||||||
|
limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the Lesser General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in
|
||||||
|
detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a license
|
||||||
|
version number, you may choose any version ever published by the Free
|
||||||
|
Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free Software
|
||||||
|
Foundation; we sometimes make exceptions for this. Our decision will be
|
||||||
|
guided by the two goals of preserving the free status of all
|
||||||
|
derivatives of our free software and of promoting the sharing and reuse
|
||||||
|
of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||||
|
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
||||||
|
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH
|
||||||
|
YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
|
||||||
|
NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
|
||||||
|
DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
|
||||||
|
DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY
|
||||||
|
(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
|
||||||
|
INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
|
||||||
|
THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR
|
||||||
|
OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
one line to give the library's name and an idea of what it does.
|
||||||
|
Copyright (C) year name of author
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or (at
|
||||||
|
your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this library; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add
|
||||||
|
information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in
|
||||||
|
the library `Frob' (a library for tweaking knobs) written
|
||||||
|
by James Random Hacker.
|
||||||
|
|
||||||
|
signature of Ty Coon, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
That's all there is to it!
|
||||||
50
README.md
50
README.md
@@ -16,7 +16,10 @@ Other header files at this repo (`include/linux/*.h`) are reduced versions of
|
|||||||
their counterpart files at bpf-next's `tools/include/linux/*.h` to make compilation
|
their counterpart files at bpf-next's `tools/include/linux/*.h` to make compilation
|
||||||
successful.
|
successful.
|
||||||
|
|
||||||
Build [](https://travis-ci.org/libbpf/libbpf)
|
Build
|
||||||
|
[](https://travis-ci.org/libbpf/libbpf)
|
||||||
|
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
||||||
|
[](https://scan.coverity.com/projects/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.
|
||||||
@@ -48,23 +51,32 @@ $ cd src
|
|||||||
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
||||||
```
|
```
|
||||||
|
|
||||||
To integrate libbpf into a project which uses Meson building system define
|
Distributions
|
||||||
`[wrap-git]` file in `subprojects` folder.
|
=====
|
||||||
To add libbpf dependency to the parent parent project, e.g. for
|
|
||||||
libbpf_static_dep:
|
|
||||||
```
|
|
||||||
libbpf_obj = subproject('libbpf', required : true)
|
|
||||||
libbpf_static_dep = libbpf_proj.get_variable('libbpf_static_dep')
|
|
||||||
```
|
|
||||||
|
|
||||||
To validate changes to meson.build
|
Distributions packaging libbpf from this mirror:
|
||||||
```bash
|
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
||||||
$ python3 meson.py build
|
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||||
$ ninja -C build/
|
|
||||||
```
|
|
||||||
|
|
||||||
To install headers, libs and pkgconfig
|
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||||
```bash
|
- Consistent versioning across distributions.
|
||||||
$ cd build
|
- No ties to any specific kernel, transparent handling of older kernels.
|
||||||
$ ninja install
|
Libbpf is designed to be kernel-agnostic and work across multitude of kernel
|
||||||
```
|
versions. It has built-in mechanisms to gracefully handle older kernels,
|
||||||
|
that are missing some of the features, by working around or gracefully
|
||||||
|
degrading functionality. Thus libbpf is not tied to a specific kernel
|
||||||
|
version and can/should be packaged and versioned independently.
|
||||||
|
- Continuous integration testing via [TravisCI](https://travis-ci.org/libbpf/libbpf).
|
||||||
|
- Static code analysis via [LGTM](https://lgtm.com/projects/g/libbpf/libbpf) and [Coverity](https://scan.coverity.com/projects/libbpf).
|
||||||
|
|
||||||
|
Package dependencies of libbpf, package names may vary across distros:
|
||||||
|
- zlib
|
||||||
|
- libelf
|
||||||
|
|
||||||
|
License
|
||||||
|
=====
|
||||||
|
|
||||||
|
This work is dual-licensed under BSD 2-clause license and GNU LGPL v2.1 license.
|
||||||
|
You can choose between one of them if you use this work.
|
||||||
|
|
||||||
|
`SPDX-License-Identifier: BSD-2-Clause OR LGPL-2.1`
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
MAP_FD, 0)
|
MAP_FD, 0)
|
||||||
|
|
||||||
#define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
|
#define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
|
||||||
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_FD, 0, 0, \
|
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_VALUE, 0, 0, \
|
||||||
MAP_FD, VALUE_OFF)
|
MAP_FD, VALUE_OFF)
|
||||||
|
|
||||||
#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
|
#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
|
||||||
@@ -107,5 +107,12 @@
|
|||||||
.off = OFF, \
|
.off = OFF, \
|
||||||
.imm = IMM })
|
.imm = IMM })
|
||||||
|
|
||||||
|
#define BPF_JMP32_IMM(OP, DST, IMM, OFF) \
|
||||||
|
((struct bpf_insn) { \
|
||||||
|
.code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \
|
||||||
|
.dst_reg = DST, \
|
||||||
|
.src_reg = 0, \
|
||||||
|
.off = OFF, \
|
||||||
|
.imm = IMM })
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -106,6 +106,11 @@ enum bpf_cmd {
|
|||||||
BPF_TASK_FD_QUERY,
|
BPF_TASK_FD_QUERY,
|
||||||
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
||||||
BPF_MAP_FREEZE,
|
BPF_MAP_FREEZE,
|
||||||
|
BPF_BTF_GET_NEXT_ID,
|
||||||
|
BPF_MAP_LOOKUP_BATCH,
|
||||||
|
BPF_MAP_LOOKUP_AND_DELETE_BATCH,
|
||||||
|
BPF_MAP_UPDATE_BATCH,
|
||||||
|
BPF_MAP_DELETE_BATCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_map_type {
|
enum bpf_map_type {
|
||||||
@@ -134,6 +139,8 @@ enum bpf_map_type {
|
|||||||
BPF_MAP_TYPE_QUEUE,
|
BPF_MAP_TYPE_QUEUE,
|
||||||
BPF_MAP_TYPE_STACK,
|
BPF_MAP_TYPE_STACK,
|
||||||
BPF_MAP_TYPE_SK_STORAGE,
|
BPF_MAP_TYPE_SK_STORAGE,
|
||||||
|
BPF_MAP_TYPE_DEVMAP_HASH,
|
||||||
|
BPF_MAP_TYPE_STRUCT_OPS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Note that tracing related programs such as
|
/* Note that tracing related programs such as
|
||||||
@@ -171,6 +178,9 @@ enum bpf_prog_type {
|
|||||||
BPF_PROG_TYPE_CGROUP_SYSCTL,
|
BPF_PROG_TYPE_CGROUP_SYSCTL,
|
||||||
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
|
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
|
||||||
BPF_PROG_TYPE_CGROUP_SOCKOPT,
|
BPF_PROG_TYPE_CGROUP_SOCKOPT,
|
||||||
|
BPF_PROG_TYPE_TRACING,
|
||||||
|
BPF_PROG_TYPE_STRUCT_OPS,
|
||||||
|
BPF_PROG_TYPE_EXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_attach_type {
|
enum bpf_attach_type {
|
||||||
@@ -197,6 +207,9 @@ enum bpf_attach_type {
|
|||||||
BPF_CGROUP_UDP6_RECVMSG,
|
BPF_CGROUP_UDP6_RECVMSG,
|
||||||
BPF_CGROUP_GETSOCKOPT,
|
BPF_CGROUP_GETSOCKOPT,
|
||||||
BPF_CGROUP_SETSOCKOPT,
|
BPF_CGROUP_SETSOCKOPT,
|
||||||
|
BPF_TRACE_RAW_TP,
|
||||||
|
BPF_TRACE_FENTRY,
|
||||||
|
BPF_TRACE_FEXIT,
|
||||||
__MAX_BPF_ATTACH_TYPE
|
__MAX_BPF_ATTACH_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -225,6 +238,11 @@ enum bpf_attach_type {
|
|||||||
* When children program makes decision (like picking TCP CA or sock bind)
|
* When children program makes decision (like picking TCP CA or sock bind)
|
||||||
* parent program has a chance to override it.
|
* parent program has a chance to override it.
|
||||||
*
|
*
|
||||||
|
* With BPF_F_ALLOW_MULTI a new program is added to the end of the list of
|
||||||
|
* programs for a cgroup. Though it's possible to replace an old program at
|
||||||
|
* any position by also specifying BPF_F_REPLACE flag and position itself in
|
||||||
|
* replace_bpf_fd attribute. Old program at this position will be released.
|
||||||
|
*
|
||||||
* A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups.
|
* A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups.
|
||||||
* A cgroup with NONE doesn't allow any programs in sub-cgroups.
|
* A cgroup with NONE doesn't allow any programs in sub-cgroups.
|
||||||
* Ex1:
|
* Ex1:
|
||||||
@@ -243,6 +261,7 @@ enum bpf_attach_type {
|
|||||||
*/
|
*/
|
||||||
#define BPF_F_ALLOW_OVERRIDE (1U << 0)
|
#define BPF_F_ALLOW_OVERRIDE (1U << 0)
|
||||||
#define BPF_F_ALLOW_MULTI (1U << 1)
|
#define BPF_F_ALLOW_MULTI (1U << 1)
|
||||||
|
#define BPF_F_REPLACE (1U << 2)
|
||||||
|
|
||||||
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
|
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
|
||||||
* verifier will perform strict alignment checking as if the kernel
|
* verifier will perform strict alignment checking as if the kernel
|
||||||
@@ -283,6 +302,9 @@ enum bpf_attach_type {
|
|||||||
*/
|
*/
|
||||||
#define BPF_F_TEST_RND_HI32 (1U << 2)
|
#define BPF_F_TEST_RND_HI32 (1U << 2)
|
||||||
|
|
||||||
|
/* The verifier internal test flag. Behavior is undefined */
|
||||||
|
#define BPF_F_TEST_STATE_FREQ (1U << 3)
|
||||||
|
|
||||||
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
||||||
* two extensions:
|
* two extensions:
|
||||||
*
|
*
|
||||||
@@ -336,7 +358,18 @@ enum bpf_attach_type {
|
|||||||
#define BPF_F_RDONLY_PROG (1U << 7)
|
#define BPF_F_RDONLY_PROG (1U << 7)
|
||||||
#define BPF_F_WRONLY_PROG (1U << 8)
|
#define BPF_F_WRONLY_PROG (1U << 8)
|
||||||
|
|
||||||
/* flags for BPF_PROG_QUERY */
|
/* Clone map from listener for newly accepted socket */
|
||||||
|
#define BPF_F_CLONE (1U << 9)
|
||||||
|
|
||||||
|
/* Enable memory-mapping BPF map */
|
||||||
|
#define BPF_F_MMAPABLE (1U << 10)
|
||||||
|
|
||||||
|
/* Flags for BPF_PROG_QUERY. */
|
||||||
|
|
||||||
|
/* Query effective (directly attached + inherited from ancestor cgroups)
|
||||||
|
* programs that will be executed for events within a cgroup.
|
||||||
|
* attach_flags with this flag are returned only for directly attached programs.
|
||||||
|
*/
|
||||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||||
|
|
||||||
enum bpf_stack_build_id_status {
|
enum bpf_stack_build_id_status {
|
||||||
@@ -376,6 +409,10 @@ union bpf_attr {
|
|||||||
__u32 btf_fd; /* fd pointing to a BTF type data */
|
__u32 btf_fd; /* fd pointing to a BTF type data */
|
||||||
__u32 btf_key_type_id; /* BTF type_id of the key */
|
__u32 btf_key_type_id; /* BTF type_id of the key */
|
||||||
__u32 btf_value_type_id; /* BTF type_id of the value */
|
__u32 btf_value_type_id; /* BTF type_id of the value */
|
||||||
|
__u32 btf_vmlinux_value_type_id;/* BTF type_id of a kernel-
|
||||||
|
* struct stored as the
|
||||||
|
* map value
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||||
@@ -388,6 +425,23 @@ union bpf_attr {
|
|||||||
__u64 flags;
|
__u64 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct { /* struct used by BPF_MAP_*_BATCH commands */
|
||||||
|
__aligned_u64 in_batch; /* start batch,
|
||||||
|
* NULL to start from beginning
|
||||||
|
*/
|
||||||
|
__aligned_u64 out_batch; /* output: next start batch */
|
||||||
|
__aligned_u64 keys;
|
||||||
|
__aligned_u64 values;
|
||||||
|
__u32 count; /* input/output:
|
||||||
|
* input: # of key/value
|
||||||
|
* elements
|
||||||
|
* output: # of filled elements
|
||||||
|
*/
|
||||||
|
__u32 map_fd;
|
||||||
|
__u64 elem_flags;
|
||||||
|
__u64 flags;
|
||||||
|
} batch;
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_PROG_LOAD command */
|
struct { /* anonymous struct used by BPF_PROG_LOAD command */
|
||||||
__u32 prog_type; /* one of enum bpf_prog_type */
|
__u32 prog_type; /* one of enum bpf_prog_type */
|
||||||
__u32 insn_cnt;
|
__u32 insn_cnt;
|
||||||
@@ -412,6 +466,8 @@ union bpf_attr {
|
|||||||
__u32 line_info_rec_size; /* userspace bpf_line_info size */
|
__u32 line_info_rec_size; /* userspace bpf_line_info size */
|
||||||
__aligned_u64 line_info; /* line info */
|
__aligned_u64 line_info; /* line info */
|
||||||
__u32 line_info_cnt; /* number of bpf_line_info records */
|
__u32 line_info_cnt; /* number of bpf_line_info records */
|
||||||
|
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
||||||
|
__u32 attach_prog_fd; /* 0 to attach to vmlinux */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
@@ -425,6 +481,10 @@ union bpf_attr {
|
|||||||
__u32 attach_bpf_fd; /* eBPF program to attach */
|
__u32 attach_bpf_fd; /* eBPF program to attach */
|
||||||
__u32 attach_type;
|
__u32 attach_type;
|
||||||
__u32 attach_flags;
|
__u32 attach_flags;
|
||||||
|
__u32 replace_bpf_fd; /* previously attached eBPF
|
||||||
|
* program to replace if
|
||||||
|
* BPF_F_REPLACE is used
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
||||||
@@ -552,10 +612,13 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
* int bpf_probe_read(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
* Description
|
* Description
|
||||||
* For tracing programs, safely attempt to read *size* bytes from
|
* For tracing programs, safely attempt to read *size* bytes from
|
||||||
* address *src* and store the data in *dst*.
|
* kernel space address *unsafe_ptr* and store the data in *dst*.
|
||||||
|
*
|
||||||
|
* Generally, use bpf_probe_read_user() or bpf_probe_read_kernel()
|
||||||
|
* instead.
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
@@ -575,6 +638,8 @@ union bpf_attr {
|
|||||||
* 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
|
||||||
|
* open, use *\/sys/kernel/debug/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/debug/tracing/trace_options* (see also the
|
||||||
@@ -784,7 +849,7 @@ union bpf_attr {
|
|||||||
* A 64-bit integer containing the current GID and UID, and
|
* A 64-bit integer containing the current GID and UID, and
|
||||||
* created as such: *current_gid* **<< 32 \|** *current_uid*.
|
* created as such: *current_gid* **<< 32 \|** *current_uid*.
|
||||||
*
|
*
|
||||||
* int bpf_get_current_comm(char *buf, u32 size_of_buf)
|
* int bpf_get_current_comm(void *buf, u32 size_of_buf)
|
||||||
* Description
|
* Description
|
||||||
* Copy the **comm** attribute of the current task into *buf* of
|
* Copy the **comm** attribute of the current task into *buf* of
|
||||||
* *size_of_buf*. The **comm** attribute contains the name of
|
* *size_of_buf*. The **comm** attribute contains the name of
|
||||||
@@ -1013,7 +1078,7 @@ union bpf_attr {
|
|||||||
* The realm of the route for the packet associated to *skb*, or 0
|
* The realm of the route for the packet associated to *skb*, or 0
|
||||||
* if none was found.
|
* if none was found.
|
||||||
*
|
*
|
||||||
* int bpf_perf_event_output(struct pt_reg *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
* int bpf_perf_event_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
||||||
* Description
|
* Description
|
||||||
* Write raw *data* blob into a special BPF perf event held by
|
* Write raw *data* blob into a special BPF perf event held by
|
||||||
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
||||||
@@ -1058,7 +1123,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len)
|
* int bpf_skb_load_bytes(const void *skb, u32 offset, void *to, u32 len)
|
||||||
* Description
|
* Description
|
||||||
* This helper was provided as an easy way to load data from a
|
* This helper was provided as an easy way to load data from a
|
||||||
* packet. It can be used to load *len* bytes from *offset* from
|
* packet. It can be used to load *len* bytes from *offset* from
|
||||||
@@ -1075,7 +1140,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_get_stackid(struct pt_reg *ctx, struct bpf_map *map, u64 flags)
|
* int bpf_get_stackid(void *ctx, struct bpf_map *map, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Walk a user or a kernel stack and return its id. To achieve
|
* Walk a user or a kernel stack and return its id. To achieve
|
||||||
* this, the helper needs *ctx*, which is a pointer to the context
|
* this, the helper needs *ctx*, which is a pointer to the context
|
||||||
@@ -1144,7 +1209,7 @@ union bpf_attr {
|
|||||||
* The checksum result, or a negative error code in case of
|
* The checksum result, or a negative error code in case of
|
||||||
* failure.
|
* failure.
|
||||||
*
|
*
|
||||||
* int bpf_skb_get_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size)
|
* int bpf_skb_get_tunnel_opt(struct sk_buff *skb, void *opt, u32 size)
|
||||||
* Description
|
* Description
|
||||||
* Retrieve tunnel options metadata for the packet associated to
|
* Retrieve tunnel options metadata for the packet associated to
|
||||||
* *skb*, and store the raw tunnel option data to the buffer *opt*
|
* *skb*, and store the raw tunnel option data to the buffer *opt*
|
||||||
@@ -1162,7 +1227,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* The size of the option data retrieved.
|
* The size of the option data retrieved.
|
||||||
*
|
*
|
||||||
* int bpf_skb_set_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size)
|
* int bpf_skb_set_tunnel_opt(struct sk_buff *skb, void *opt, u32 size)
|
||||||
* Description
|
* Description
|
||||||
* Set tunnel options metadata for the packet associated to *skb*
|
* Set tunnel options metadata for the packet associated to *skb*
|
||||||
* to the option data contained in the raw buffer *opt* of *size*.
|
* to the option data contained in the raw buffer *opt* of *size*.
|
||||||
@@ -1415,45 +1480,14 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
|
* int bpf_probe_read_str(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
* Description
|
* Description
|
||||||
* Copy a NUL terminated string from an unsafe address
|
* Copy a NUL terminated string from an unsafe kernel address
|
||||||
* *unsafe_ptr* to *dst*. The *size* should include the
|
* *unsafe_ptr* to *dst*. See bpf_probe_read_kernel_str() for
|
||||||
* terminating NUL byte. In case the string length is smaller than
|
* more details.
|
||||||
* *size*, the target is not padded with further NUL bytes. If the
|
|
||||||
* string length is larger than *size*, just *size*-1 bytes are
|
|
||||||
* copied and the last byte is set to NUL.
|
|
||||||
*
|
*
|
||||||
* On success, the length of the copied string is returned. This
|
* Generally, use bpf_probe_read_user_str() or bpf_probe_read_kernel_str()
|
||||||
* makes this helper useful in tracing programs for reading
|
* instead.
|
||||||
* strings, and more importantly to get its length at runtime. See
|
|
||||||
* the following snippet:
|
|
||||||
*
|
|
||||||
* ::
|
|
||||||
*
|
|
||||||
* SEC("kprobe/sys_open")
|
|
||||||
* void bpf_sys_open(struct pt_regs *ctx)
|
|
||||||
* {
|
|
||||||
* char buf[PATHLEN]; // PATHLEN is defined to 256
|
|
||||||
* int res = bpf_probe_read_str(buf, sizeof(buf),
|
|
||||||
* ctx->di);
|
|
||||||
*
|
|
||||||
* // Consume buf, for example push it to
|
|
||||||
* // userspace via bpf_perf_event_output(); we
|
|
||||||
* // can use res (the string length) as event
|
|
||||||
* // size, after checking its boundaries.
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* In comparison, using **bpf_probe_read()** helper here instead
|
|
||||||
* to read the string would require to estimate the length at
|
|
||||||
* compile time, and would often result in copying more memory
|
|
||||||
* than necessary.
|
|
||||||
*
|
|
||||||
* Another useful use case is when parsing individual process
|
|
||||||
* arguments or individual environment variables navigating
|
|
||||||
* *current*\ **->mm->arg_start** and *current*\
|
|
||||||
* **->mm->env_start**: using this helper and the return value,
|
|
||||||
* one can quickly iterate at the right offset of the memory area.
|
|
||||||
* Return
|
* Return
|
||||||
* On success, the strictly positive length of the string,
|
* On success, the strictly positive length of the string,
|
||||||
* including the trailing NUL character. On error, a negative
|
* including the trailing NUL character. On error, a negative
|
||||||
@@ -1466,8 +1500,8 @@ union bpf_attr {
|
|||||||
* If no cookie has been set yet, generate a new cookie. Once
|
* If no cookie has been set yet, generate a new cookie. Once
|
||||||
* generated, the socket cookie remains stable for the life of the
|
* generated, the socket cookie remains stable for the life of the
|
||||||
* socket. This helper can be useful for monitoring per socket
|
* socket. This helper can be useful for monitoring per socket
|
||||||
* networking traffic statistics as it provides a unique socket
|
* networking traffic statistics as it provides a global socket
|
||||||
* identifier per namespace.
|
* identifier that can be assumed unique.
|
||||||
* Return
|
* Return
|
||||||
* A 8-byte long non-decreasing number on success, or 0 if the
|
* A 8-byte long non-decreasing number on success, or 0 if the
|
||||||
* socket field is missing inside *skb*.
|
* socket field is missing inside *skb*.
|
||||||
@@ -1501,7 +1535,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0
|
* 0
|
||||||
*
|
*
|
||||||
* int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen)
|
* int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen)
|
||||||
* Description
|
* Description
|
||||||
* Emulate a call to **setsockopt()** on the socket associated to
|
* Emulate a call to **setsockopt()** on the socket associated to
|
||||||
* *bpf_socket*, which must be a full socket. The *level* at
|
* *bpf_socket*, which must be a full socket. The *level* at
|
||||||
@@ -1571,8 +1605,11 @@ union bpf_attr {
|
|||||||
* but this is only implemented for native XDP (with driver
|
* but this is only implemented for native XDP (with driver
|
||||||
* support) as of this writing).
|
* support) as of this writing).
|
||||||
*
|
*
|
||||||
* All values for *flags* are reserved for future usage, and must
|
* The lower two bits of *flags* are used as the return code if
|
||||||
* be left at zero.
|
* the map lookup fails. This is so that the return value can be
|
||||||
|
* one of the XDP program return codes up to XDP_TX, as chosen by
|
||||||
|
* the caller. Any higher bits in the *flags* argument must be
|
||||||
|
* unset.
|
||||||
*
|
*
|
||||||
* When used to redirect packets to net devices, this helper
|
* When used to redirect packets to net devices, this helper
|
||||||
* provides a high performance increase over **bpf_redirect**\ ().
|
* provides a high performance increase over **bpf_redirect**\ ().
|
||||||
@@ -1582,7 +1619,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* **XDP_REDIRECT** on success, or **XDP_ABORTED** on error.
|
* **XDP_REDIRECT** on success, or **XDP_ABORTED** on error.
|
||||||
*
|
*
|
||||||
* int bpf_sk_redirect_map(struct bpf_map *map, u32 key, u64 flags)
|
* int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Redirect the packet to the socket referenced by *map* (of type
|
* Redirect the packet to the socket referenced by *map* (of type
|
||||||
* **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and
|
* **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and
|
||||||
@@ -1702,7 +1739,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen)
|
* int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen)
|
||||||
* Description
|
* Description
|
||||||
* Emulate a call to **getsockopt()** on the socket associated to
|
* Emulate a call to **getsockopt()** on the socket associated to
|
||||||
* *bpf_socket*, which must be a full socket. The *level* at
|
* *bpf_socket*, which must be a full socket. The *level* at
|
||||||
@@ -1721,7 +1758,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_override_return(struct pt_reg *regs, u64 rc)
|
* int bpf_override_return(struct pt_regs *regs, u64 rc)
|
||||||
* Description
|
* Description
|
||||||
* Used for error injection, this helper uses kprobes to override
|
* Used for error injection, this helper uses kprobes to override
|
||||||
* the return value of the probed function, and to set it to *rc*.
|
* the return value of the probed function, and to set it to *rc*.
|
||||||
@@ -1934,7 +1971,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags)
|
* int bpf_get_stack(void *ctx, void *buf, u32 size, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Return a user or a kernel stack in bpf program provided buffer.
|
* Return a user or a kernel stack in bpf program provided buffer.
|
||||||
* To achieve this, the helper needs *ctx*, which is a pointer
|
* To achieve this, the helper needs *ctx*, which is a pointer
|
||||||
@@ -1967,7 +2004,7 @@ union bpf_attr {
|
|||||||
* A non-negative value equal to or less than *size* on success,
|
* A non-negative value equal to or less than *size* on success,
|
||||||
* or a negative error in case of failure.
|
* or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header)
|
* int bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header)
|
||||||
* Description
|
* Description
|
||||||
* This helper is similar to **bpf_skb_load_bytes**\ () in that
|
* This helper is similar to **bpf_skb_load_bytes**\ () in that
|
||||||
* it provides an easy way to load *len* bytes from *offset*
|
* it provides an easy way to load *len* bytes from *offset*
|
||||||
@@ -2020,7 +2057,7 @@ union bpf_attr {
|
|||||||
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
||||||
* packet is not forwarded or needs assist from full stack
|
* packet is not forwarded or needs assist from full stack
|
||||||
*
|
*
|
||||||
* int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags)
|
* int bpf_sock_hash_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Add an entry to, or update a sockhash *map* referencing sockets.
|
* Add an entry to, or update a sockhash *map* referencing sockets.
|
||||||
* The *skops* is used as a new value for the entry associated to
|
* The *skops* is used as a new value for the entry associated to
|
||||||
@@ -2379,7 +2416,7 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
* int bpf_msg_push_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* For socket policies, insert *len* bytes into *msg* at offset
|
* For socket policies, insert *len* bytes into *msg* at offset
|
||||||
* *start*.
|
* *start*.
|
||||||
@@ -2395,9 +2432,9 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags)
|
* int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Will remove *pop* bytes from a *msg* starting at byte *start*.
|
* Will remove *len* bytes from a *msg* starting at byte *start*.
|
||||||
* This may result in **ENOMEM** errors under certain situations if
|
* This may result in **ENOMEM** errors under certain situations if
|
||||||
* an allocation and copy are required due to a full ring buffer.
|
* an allocation and copy are required due to a full ring buffer.
|
||||||
* However, the helper will try to avoid doing the allocation
|
* However, the helper will try to avoid doing the allocation
|
||||||
@@ -2492,7 +2529,7 @@ union bpf_attr {
|
|||||||
* A **struct bpf_tcp_sock** pointer on success, or **NULL** in
|
* A **struct bpf_tcp_sock** pointer on success, or **NULL** in
|
||||||
* case of failure.
|
* case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_skb_ecn_set_ce(struct sk_buf *skb)
|
* int bpf_skb_ecn_set_ce(struct sk_buff *skb)
|
||||||
* Description
|
* Description
|
||||||
* Set ECN (Explicit Congestion Notification) field of IP header
|
* Set ECN (Explicit Congestion Notification) field of IP header
|
||||||
* to **CE** (Congestion Encountered) if current value is **ECT**
|
* to **CE** (Congestion Encountered) if current value is **ECT**
|
||||||
@@ -2699,7 +2736,8 @@ union bpf_attr {
|
|||||||
*
|
*
|
||||||
* int bpf_send_signal(u32 sig)
|
* int bpf_send_signal(u32 sig)
|
||||||
* Description
|
* Description
|
||||||
* Send signal *sig* to the current task.
|
* Send signal *sig* to the process of the current task.
|
||||||
|
* The signal may be delivered to any of this process's threads.
|
||||||
* Return
|
* Return
|
||||||
* 0 on success or successfully queued.
|
* 0 on success or successfully queued.
|
||||||
*
|
*
|
||||||
@@ -2710,6 +2748,150 @@ union bpf_attr {
|
|||||||
* **-EPERM** if no permission to send the *sig*.
|
* **-EPERM** if no permission to send the *sig*.
|
||||||
*
|
*
|
||||||
* **-EAGAIN** if bpf program can try again.
|
* **-EAGAIN** if bpf program can try again.
|
||||||
|
*
|
||||||
|
* s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
|
||||||
|
* Description
|
||||||
|
* Try to issue a SYN cookie for the packet with corresponding
|
||||||
|
* IP/TCP headers, *iph* and *th*, on the listening socket in *sk*.
|
||||||
|
*
|
||||||
|
* *iph* points to the start of the IPv4 or IPv6 header, while
|
||||||
|
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
|
||||||
|
* **sizeof**\ (**struct ip6hdr**).
|
||||||
|
*
|
||||||
|
* *th* points to the start of the TCP header, while *th_len*
|
||||||
|
* contains the length of the TCP header.
|
||||||
|
*
|
||||||
|
* Return
|
||||||
|
* On success, lower 32 bits hold the generated SYN cookie in
|
||||||
|
* followed by 16 bits which hold the MSS value for that cookie,
|
||||||
|
* and the top 16 bits are unused.
|
||||||
|
*
|
||||||
|
* On failure, the returned value is one of the following:
|
||||||
|
*
|
||||||
|
* **-EINVAL** SYN cookie cannot be issued due to error
|
||||||
|
*
|
||||||
|
* **-ENOENT** SYN cookie should not be issued (no SYN flood)
|
||||||
|
*
|
||||||
|
* **-EOPNOTSUPP** kernel configuration does not enable SYN cookies
|
||||||
|
*
|
||||||
|
* **-EPROTONOSUPPORT** IP packet version is not 4 or 6
|
||||||
|
*
|
||||||
|
* int bpf_skb_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
||||||
|
* Description
|
||||||
|
* Write raw *data* blob into a special BPF perf event held by
|
||||||
|
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
||||||
|
* event must have the following attributes: **PERF_SAMPLE_RAW**
|
||||||
|
* as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and
|
||||||
|
* **PERF_COUNT_SW_BPF_OUTPUT** as **config**.
|
||||||
|
*
|
||||||
|
* The *flags* are used to indicate the index in *map* for which
|
||||||
|
* the value must be put, masked with **BPF_F_INDEX_MASK**.
|
||||||
|
* Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU**
|
||||||
|
* to indicate that the index of the current CPU core should be
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* The value to write, of *size*, is passed through eBPF stack and
|
||||||
|
* pointed by *data*.
|
||||||
|
*
|
||||||
|
* *ctx* is a pointer to in-kernel struct sk_buff.
|
||||||
|
*
|
||||||
|
* This helper is similar to **bpf_perf_event_output**\ () but
|
||||||
|
* restricted to raw_tracepoint bpf programs.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_probe_read_user(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
|
* Description
|
||||||
|
* Safely attempt to read *size* bytes from user space address
|
||||||
|
* *unsafe_ptr* and store the data in *dst*.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_probe_read_kernel(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
|
* Description
|
||||||
|
* Safely attempt to read *size* bytes from kernel space address
|
||||||
|
* *unsafe_ptr* and store the data in *dst*.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_probe_read_user_str(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
|
* Description
|
||||||
|
* Copy a NUL terminated string from an unsafe user address
|
||||||
|
* *unsafe_ptr* to *dst*. The *size* should include the
|
||||||
|
* terminating NUL byte. In case the string length is smaller than
|
||||||
|
* *size*, the target is not padded with further NUL bytes. If the
|
||||||
|
* string length is larger than *size*, just *size*-1 bytes are
|
||||||
|
* copied and the last byte is set to NUL.
|
||||||
|
*
|
||||||
|
* On success, the length of the copied string is returned. This
|
||||||
|
* makes this helper useful in tracing programs for reading
|
||||||
|
* strings, and more importantly to get its length at runtime. See
|
||||||
|
* the following snippet:
|
||||||
|
*
|
||||||
|
* ::
|
||||||
|
*
|
||||||
|
* SEC("kprobe/sys_open")
|
||||||
|
* void bpf_sys_open(struct pt_regs *ctx)
|
||||||
|
* {
|
||||||
|
* char buf[PATHLEN]; // PATHLEN is defined to 256
|
||||||
|
* int res = bpf_probe_read_user_str(buf, sizeof(buf),
|
||||||
|
* ctx->di);
|
||||||
|
*
|
||||||
|
* // Consume buf, for example push it to
|
||||||
|
* // userspace via bpf_perf_event_output(); we
|
||||||
|
* // can use res (the string length) as event
|
||||||
|
* // size, after checking its boundaries.
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* In comparison, using **bpf_probe_read_user()** helper here
|
||||||
|
* instead to read the string would require to estimate the length
|
||||||
|
* at compile time, and would often result in copying more memory
|
||||||
|
* than necessary.
|
||||||
|
*
|
||||||
|
* Another useful use case is when parsing individual process
|
||||||
|
* arguments or individual environment variables navigating
|
||||||
|
* *current*\ **->mm->arg_start** and *current*\
|
||||||
|
* **->mm->env_start**: using this helper and the return value,
|
||||||
|
* one can quickly iterate at the right offset of the memory area.
|
||||||
|
* Return
|
||||||
|
* On success, the strictly positive length of the string,
|
||||||
|
* including the trailing NUL character. On error, a negative
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* int bpf_probe_read_kernel_str(void *dst, u32 size, const void *unsafe_ptr)
|
||||||
|
* Description
|
||||||
|
* Copy a NUL terminated string from an unsafe kernel address *unsafe_ptr*
|
||||||
|
* to *dst*. Same semantics as with bpf_probe_read_user_str() apply.
|
||||||
|
* Return
|
||||||
|
* On success, the strictly positive length of the string, including
|
||||||
|
* the trailing NUL character. On error, a negative value.
|
||||||
|
*
|
||||||
|
* int bpf_tcp_send_ack(void *tp, u32 rcv_nxt)
|
||||||
|
* Description
|
||||||
|
* Send out a tcp-ack. *tp* is the in-kernel struct tcp_sock.
|
||||||
|
* *rcv_nxt* is the ack_seq to be sent out.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_send_signal_thread(u32 sig)
|
||||||
|
* Description
|
||||||
|
* Send signal *sig* to the thread corresponding to the current task.
|
||||||
|
* Return
|
||||||
|
* 0 on success or successfully queued.
|
||||||
|
*
|
||||||
|
* **-EBUSY** if work queue under nmi is full.
|
||||||
|
*
|
||||||
|
* **-EINVAL** if *sig* is invalid.
|
||||||
|
*
|
||||||
|
* **-EPERM** if no permission to send the *sig*.
|
||||||
|
*
|
||||||
|
* **-EAGAIN** if bpf program can try again.
|
||||||
|
*
|
||||||
|
* u64 bpf_jiffies64(void)
|
||||||
|
* Description
|
||||||
|
* Obtain the 64bit jiffies
|
||||||
|
* Return
|
||||||
|
* The 64 bit jiffies
|
||||||
*/
|
*/
|
||||||
#define __BPF_FUNC_MAPPER(FN) \
|
#define __BPF_FUNC_MAPPER(FN) \
|
||||||
FN(unspec), \
|
FN(unspec), \
|
||||||
@@ -2821,7 +3003,16 @@ union bpf_attr {
|
|||||||
FN(strtoul), \
|
FN(strtoul), \
|
||||||
FN(sk_storage_get), \
|
FN(sk_storage_get), \
|
||||||
FN(sk_storage_delete), \
|
FN(sk_storage_delete), \
|
||||||
FN(send_signal),
|
FN(send_signal), \
|
||||||
|
FN(tcp_gen_syncookie), \
|
||||||
|
FN(skb_output), \
|
||||||
|
FN(probe_read_user), \
|
||||||
|
FN(probe_read_kernel), \
|
||||||
|
FN(probe_read_user_str), \
|
||||||
|
FN(probe_read_kernel_str), \
|
||||||
|
FN(tcp_send_ack), \
|
||||||
|
FN(send_signal_thread), \
|
||||||
|
FN(jiffies64),
|
||||||
|
|
||||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||||
* function eBPF program intends to call
|
* function eBPF program intends to call
|
||||||
@@ -3222,7 +3413,7 @@ struct bpf_map_info {
|
|||||||
__u32 map_flags;
|
__u32 map_flags;
|
||||||
char name[BPF_OBJ_NAME_LEN];
|
char name[BPF_OBJ_NAME_LEN];
|
||||||
__u32 ifindex;
|
__u32 ifindex;
|
||||||
__u32 :32;
|
__u32 btf_vmlinux_value_type_id;
|
||||||
__u64 netns_dev;
|
__u64 netns_dev;
|
||||||
__u64 netns_ino;
|
__u64 netns_ino;
|
||||||
__u32 btf_id;
|
__u32 btf_id;
|
||||||
@@ -3504,6 +3695,10 @@ enum bpf_task_fd_type {
|
|||||||
BPF_FD_TYPE_URETPROBE, /* filename + offset */
|
BPF_FD_TYPE_URETPROBE, /* filename + offset */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG (1U << 0)
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL (1U << 1)
|
||||||
|
#define BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP (1U << 2)
|
||||||
|
|
||||||
struct bpf_flow_keys {
|
struct bpf_flow_keys {
|
||||||
__u16 nhoff;
|
__u16 nhoff;
|
||||||
__u16 thoff;
|
__u16 thoff;
|
||||||
@@ -3525,6 +3720,8 @@ struct bpf_flow_keys {
|
|||||||
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
__u32 flags;
|
||||||
|
__be32 flow_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_func_info {
|
struct bpf_func_info {
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ struct btf_header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Max # of type identifier */
|
/* Max # of type identifier */
|
||||||
#define BTF_MAX_TYPE 0x0000ffff
|
#define BTF_MAX_TYPE 0x000fffff
|
||||||
/* Max offset into the string section */
|
/* Max offset into the string section */
|
||||||
#define BTF_MAX_NAME_OFFSET 0x0000ffff
|
#define BTF_MAX_NAME_OFFSET 0x00ffffff
|
||||||
/* Max # of struct/union/enum members or func args */
|
/* Max # of struct/union/enum members or func args */
|
||||||
#define BTF_MAX_VLEN 0xffff
|
#define BTF_MAX_VLEN 0xffff
|
||||||
|
|
||||||
@@ -142,7 +142,14 @@ struct btf_param {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
BTF_VAR_STATIC = 0,
|
BTF_VAR_STATIC = 0,
|
||||||
BTF_VAR_GLOBAL_ALLOCATED,
|
BTF_VAR_GLOBAL_ALLOCATED = 1,
|
||||||
|
BTF_VAR_GLOBAL_EXTERN = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum btf_func_linkage {
|
||||||
|
BTF_FUNC_STATIC = 0,
|
||||||
|
BTF_FUNC_GLOBAL = 1,
|
||||||
|
BTF_FUNC_EXTERN = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* BTF_KIND_VAR is followed by a single "struct btf_var" to describe
|
/* BTF_KIND_VAR is followed by a single "struct btf_var" to describe
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ enum {
|
|||||||
IFLA_NEW_IFINDEX,
|
IFLA_NEW_IFINDEX,
|
||||||
IFLA_MIN_MTU,
|
IFLA_MIN_MTU,
|
||||||
IFLA_MAX_MTU,
|
IFLA_MAX_MTU,
|
||||||
|
IFLA_PROP_LIST,
|
||||||
|
IFLA_ALT_IFNAME, /* Alternative ifname */
|
||||||
|
IFLA_PERM_ADDRESS,
|
||||||
__IFLA_MAX
|
__IFLA_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -483,6 +486,13 @@ enum macsec_validation_type {
|
|||||||
MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
|
MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum macsec_offload {
|
||||||
|
MACSEC_OFFLOAD_OFF = 0,
|
||||||
|
MACSEC_OFFLOAD_PHY = 1,
|
||||||
|
__MACSEC_OFFLOAD_END,
|
||||||
|
MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* IPVLAN section */
|
/* IPVLAN section */
|
||||||
enum {
|
enum {
|
||||||
IFLA_IPVLAN_UNSPEC,
|
IFLA_IPVLAN_UNSPEC,
|
||||||
@@ -695,6 +705,7 @@ enum {
|
|||||||
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
|
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
|
||||||
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
|
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
|
||||||
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
|
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
|
||||||
|
IFLA_VF_BROADCAST, /* VF broadcast */
|
||||||
__IFLA_VF_MAX,
|
__IFLA_VF_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -705,6 +716,10 @@ struct ifla_vf_mac {
|
|||||||
__u8 mac[32]; /* MAX_ADDR_LEN */
|
__u8 mac[32]; /* MAX_ADDR_LEN */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ifla_vf_broadcast {
|
||||||
|
__u8 broadcast[32];
|
||||||
|
};
|
||||||
|
|
||||||
struct ifla_vf_vlan {
|
struct ifla_vf_vlan {
|
||||||
__u32 vf;
|
__u32 vf;
|
||||||
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
||||||
|
|||||||
@@ -16,6 +16,18 @@
|
|||||||
#define XDP_SHARED_UMEM (1 << 0)
|
#define XDP_SHARED_UMEM (1 << 0)
|
||||||
#define XDP_COPY (1 << 1) /* Force copy-mode */
|
#define XDP_COPY (1 << 1) /* Force copy-mode */
|
||||||
#define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
|
#define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
|
||||||
|
/* If this option is set, the driver might go sleep and in that case
|
||||||
|
* the XDP_RING_NEED_WAKEUP flag in the fill and/or Tx rings will be
|
||||||
|
* set. If it is set, the application need to explicitly wake up the
|
||||||
|
* driver with a poll() (Rx and Tx) or sendto() (Tx only). If you are
|
||||||
|
* running the driver and the application on the same core, you should
|
||||||
|
* use this option so that the kernel will yield to the user space
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
#define XDP_USE_NEED_WAKEUP (1 << 3)
|
||||||
|
|
||||||
|
/* Flags for xsk_umem_config flags */
|
||||||
|
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||||
|
|
||||||
struct sockaddr_xdp {
|
struct sockaddr_xdp {
|
||||||
__u16 sxdp_family;
|
__u16 sxdp_family;
|
||||||
@@ -25,10 +37,14 @@ struct sockaddr_xdp {
|
|||||||
__u32 sxdp_shared_umem_fd;
|
__u32 sxdp_shared_umem_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* XDP_RING flags */
|
||||||
|
#define XDP_RING_NEED_WAKEUP (1 << 0)
|
||||||
|
|
||||||
struct xdp_ring_offset {
|
struct xdp_ring_offset {
|
||||||
__u64 producer;
|
__u64 producer;
|
||||||
__u64 consumer;
|
__u64 consumer;
|
||||||
__u64 desc;
|
__u64 desc;
|
||||||
|
__u64 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdp_mmap_offsets {
|
struct xdp_mmap_offsets {
|
||||||
@@ -53,6 +69,7 @@ struct xdp_umem_reg {
|
|||||||
__u64 len; /* Length of packet data area */
|
__u64 len; /* Length of packet data area */
|
||||||
__u32 chunk_size;
|
__u32 chunk_size;
|
||||||
__u32 headroom;
|
__u32 headroom;
|
||||||
|
__u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdp_statistics {
|
struct xdp_statistics {
|
||||||
@@ -74,6 +91,11 @@ struct xdp_options {
|
|||||||
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
|
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
|
||||||
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
|
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
|
||||||
|
|
||||||
|
/* Masks for unaligned chunks mode */
|
||||||
|
#define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
|
||||||
|
#define XSK_UNALIGNED_BUF_ADDR_MASK \
|
||||||
|
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||||
|
|
||||||
/* Rx/Tx descriptor */
|
/* Rx/Tx descriptor */
|
||||||
struct xdp_desc {
|
struct xdp_desc {
|
||||||
__u64 addr;
|
__u64 addr;
|
||||||
|
|||||||
95
meson.build
95
meson.build
@@ -1,95 +0,0 @@
|
|||||||
# SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
|
|
||||||
project('libbpf', 'c',
|
|
||||||
version : '0.0.3',
|
|
||||||
license : 'LGPL-2.1 OR BSD-2-Clause',
|
|
||||||
default_options : [
|
|
||||||
'prefix=/usr',
|
|
||||||
],
|
|
||||||
meson_version : '>= 0.46',
|
|
||||||
)
|
|
||||||
|
|
||||||
patchlevel = meson.project_version().split('.')[1]
|
|
||||||
|
|
||||||
libbpf_source_dir = './'
|
|
||||||
|
|
||||||
libbpf_sources = files(run_command('find',
|
|
||||||
[
|
|
||||||
'@0@/src'.format(libbpf_source_dir),
|
|
||||||
'-type',
|
|
||||||
'f',
|
|
||||||
'-name',
|
|
||||||
'*.[h|c]']).stdout().split())
|
|
||||||
|
|
||||||
libbpf_headers = files(
|
|
||||||
join_paths(libbpf_source_dir, 'src/bpf.h'),
|
|
||||||
join_paths(libbpf_source_dir, 'src/btf.h'),
|
|
||||||
join_paths(libbpf_source_dir, 'src/libbpf.h'))
|
|
||||||
|
|
||||||
feature_rellocarray = run_command(join_paths(libbpf_source_dir, 'scripts/check-reallocarray.sh'))
|
|
||||||
|
|
||||||
libbpf_c_args = ['-g',
|
|
||||||
'-O2',
|
|
||||||
'-Werror',
|
|
||||||
'-Wall',
|
|
||||||
]
|
|
||||||
|
|
||||||
if feature_rellocarray.stdout().strip() != ''
|
|
||||||
libbpf_c_args += '-DCOMPAT_NEED_REALLOCARRAY'
|
|
||||||
endif
|
|
||||||
|
|
||||||
# bpf_includes are required to include bpf.h, btf.h, libbpf.h
|
|
||||||
bpf_includes = include_directories(
|
|
||||||
join_paths(libbpf_source_dir, 'src'))
|
|
||||||
|
|
||||||
libbpf_includes = include_directories(
|
|
||||||
join_paths(libbpf_source_dir, 'include'),
|
|
||||||
join_paths(libbpf_source_dir, 'include/uapi'))
|
|
||||||
|
|
||||||
libelf = dependency('libelf')
|
|
||||||
libelf = dependency('libelf', required: false)
|
|
||||||
if not libelf.found()
|
|
||||||
libelf = cc.find_library('elf', required: true)
|
|
||||||
endif
|
|
||||||
|
|
||||||
deps = [libelf]
|
|
||||||
|
|
||||||
libbpf_static = static_library(
|
|
||||||
'bpf',
|
|
||||||
libbpf_sources,
|
|
||||||
c_args : libbpf_c_args,
|
|
||||||
dependencies : deps,
|
|
||||||
include_directories : libbpf_includes,
|
|
||||||
install : true)
|
|
||||||
|
|
||||||
libbpf_static_dep = declare_dependency(link_with : libbpf_static)
|
|
||||||
|
|
||||||
libbpf_map_source_path = join_paths(libbpf_source_dir, 'src/libbpf.map')
|
|
||||||
libbpf_map_abs_path = join_paths(meson.current_source_dir(), libbpf_map_source_path)
|
|
||||||
|
|
||||||
libbpf_c_args += ['-fPIC', '-fvisibility=hidden']
|
|
||||||
|
|
||||||
libbpf_link_args = ['-Wl,--version-script=@0@'.format(libbpf_map_abs_path)]
|
|
||||||
|
|
||||||
libbpf_shared = shared_library(
|
|
||||||
'bpf',
|
|
||||||
libbpf_sources,
|
|
||||||
c_args : libbpf_c_args,
|
|
||||||
dependencies : deps,
|
|
||||||
include_directories : libbpf_includes,
|
|
||||||
install : true,
|
|
||||||
link_args : libbpf_link_args,
|
|
||||||
link_depends : libbpf_map_source_path,
|
|
||||||
soversion : patchlevel,
|
|
||||||
version : meson.project_version())
|
|
||||||
|
|
||||||
libbpf_shared_dep = declare_dependency(link_with : libbpf_shared)
|
|
||||||
|
|
||||||
install_headers(libbpf_headers, subdir : 'bpf')
|
|
||||||
|
|
||||||
pkg = import('pkgconfig')
|
|
||||||
pkg.generate(
|
|
||||||
name: meson.project_name(),
|
|
||||||
version: meson.project_version(),
|
|
||||||
libraries: libbpf_shared,
|
|
||||||
requires_private: ['libelf'],
|
|
||||||
description: '''BPF library''')
|
|
||||||
105
scripts/coverity.sh
Executable file
105
scripts/coverity.sh
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Taken from: https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
|
||||||
|
# Local changes are annotated with "#[local]"
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Environment check
|
||||||
|
echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
|
||||||
|
[ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
|
||||||
|
[ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
|
||||||
|
[ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
|
||||||
|
[ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
|
||||||
|
[ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1
|
||||||
|
|
||||||
|
PLATFORM=`uname`
|
||||||
|
#[local] Use /var/tmp for TOOL_ARCHIVE and TOOL_BASE, as on certain systems
|
||||||
|
# /tmp is tmpfs and is sometimes too small to handle all necessary tooling
|
||||||
|
TOOL_ARCHIVE=/var//tmp/cov-analysis-${PLATFORM}.tgz
|
||||||
|
TOOL_URL=https://scan.coverity.com/download/${PLATFORM}
|
||||||
|
TOOL_BASE=/var/tmp/coverity-scan-analysis
|
||||||
|
UPLOAD_URL="https://scan.coverity.com/builds"
|
||||||
|
SCAN_URL="https://scan.coverity.com"
|
||||||
|
|
||||||
|
# Do not run on pull requests
|
||||||
|
if [ "${TRAVIS_PULL_REQUEST}" = "true" ]; then
|
||||||
|
echo -e "\033[33;1mINFO: Skipping Coverity Analysis: branch is a pull request.\033[0m"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify this branch should run
|
||||||
|
IS_COVERITY_SCAN_BRANCH=`ruby -e "puts '${TRAVIS_BRANCH}' =~ /\\A$COVERITY_SCAN_BRANCH_PATTERN\\z/ ? 1 : 0"`
|
||||||
|
if [ "$IS_COVERITY_SCAN_BRANCH" = "1" ]; then
|
||||||
|
echo -e "\033[33;1mCoverity Scan configured to run on branch ${TRAVIS_BRANCH}\033[0m"
|
||||||
|
else
|
||||||
|
echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${TRAVIS_BRANCH}\033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify upload is permitted
|
||||||
|
AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
|
||||||
|
if [ "$AUTH_RES" = "Access denied" ]; then
|
||||||
|
echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
AUTH=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['upload_permitted']"`
|
||||||
|
if [ "$AUTH" = "true" ]; then
|
||||||
|
echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
|
||||||
|
else
|
||||||
|
WHEN=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['next_upload_permitted_at']"`
|
||||||
|
echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d $TOOL_BASE ]; then
|
||||||
|
# Download Coverity Scan Analysis Tool
|
||||||
|
if [ ! -e $TOOL_ARCHIVE ]; then
|
||||||
|
echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
|
||||||
|
wget -nv -O $TOOL_ARCHIVE $TOOL_URL --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=$COVERITY_SCAN_TOKEN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract Coverity Scan Analysis Tool
|
||||||
|
echo -e "\033[33;1mExtracting Coverity Scan Analysis Tool...\033[0m"
|
||||||
|
mkdir -p $TOOL_BASE
|
||||||
|
pushd $TOOL_BASE
|
||||||
|
tar xzf $TOOL_ARCHIVE
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
|
||||||
|
export PATH=$TOOL_DIR/bin:$PATH
|
||||||
|
|
||||||
|
# Build
|
||||||
|
echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
|
||||||
|
COV_BUILD_OPTIONS=""
|
||||||
|
#COV_BUILD_OPTIONS="--return-emit-failures 8 --parse-error-threshold 85"
|
||||||
|
RESULTS_DIR="cov-int"
|
||||||
|
eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
|
||||||
|
COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $COV_BUILD_OPTIONS $COVERITY_SCAN_BUILD_COMMAND
|
||||||
|
cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt 2>&1
|
||||||
|
|
||||||
|
# Upload results
|
||||||
|
echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
|
||||||
|
RESULTS_ARCHIVE=analysis-results.tgz
|
||||||
|
tar czf $RESULTS_ARCHIVE $RESULTS_DIR
|
||||||
|
SHA=`git rev-parse --short HEAD`
|
||||||
|
|
||||||
|
echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
|
||||||
|
response=$(curl \
|
||||||
|
--silent --write-out "\n%{http_code}\n" \
|
||||||
|
--form project=$COVERITY_SCAN_PROJECT_NAME \
|
||||||
|
--form token=$COVERITY_SCAN_TOKEN \
|
||||||
|
--form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
|
||||||
|
--form file=@$RESULTS_ARCHIVE \
|
||||||
|
--form version=$SHA \
|
||||||
|
--form description="Travis CI build" \
|
||||||
|
$UPLOAD_URL)
|
||||||
|
status_code=$(echo "$response" | sed -n '$p')
|
||||||
|
#[local] Coverity used to return 201 on success, but it's 200 now
|
||||||
|
# See https://github.com/systemd/systemd/blob/master/tools/coverity.sh#L145
|
||||||
|
if [ "$status_code" != "200" ]; then
|
||||||
|
TEXT=$(echo "$response" | sed '$d')
|
||||||
|
echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -1,40 +1,212 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo "USAGE: ./sync-kernel.sh <kernel-repo> <libbpf-repo> [<baseline-commit>]"
|
echo "USAGE: ./sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>"
|
||||||
echo ""
|
echo ""
|
||||||
echo "If <baseline-commit> is not specified, it's read from <libbpf-repo>/CHECKPOINT-COMMIT"
|
echo "Set BPF_NEXT_BASELINE to override bpf-next tree commit, otherwise read from <libbpf-repo>/CHECKPOINT-COMMIT."
|
||||||
exit 1
|
echo "Set BPF_BASELINE to override bpf tree commit, otherwise read from <libbpf-repo>/BPF-CHECKPOINT-COMMIT."
|
||||||
|
echo "Set MANUAL_MODE to 1 to manually control every cherry-picked commits."
|
||||||
|
echo "Set IGNORE_CONSISTENCY to 1 to ignore failed contents consistency check."
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
LINUX_REPO=${1-""}
|
|
||||||
LIBBPF_REPO=${2-""}
|
|
||||||
|
|
||||||
if [ -z "${LINUX_REPO}" ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
if [ -z "${LIBBPF_REPO}" ]; then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
WORKDIR=$(pwd)
|
LIBBPF_REPO=${1-""}
|
||||||
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
LINUX_REPO=${2-""}
|
||||||
|
BPF_BRANCH=${3-""}
|
||||||
|
BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||||
|
BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
|
||||||
|
|
||||||
echo "WORKDIR: ${WORKDIR}"
|
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ] || [ -z "${BPF_BRANCH}" ]; then
|
||||||
echo "LINUX REPO: ${LINUX_REPO}"
|
echo "Error: libbpf or linux repos are not specified"
|
||||||
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
usage
|
||||||
|
fi
|
||||||
|
if [ -z "${BPF_BRANCH}" ]; then
|
||||||
|
echo "Error: linux's bpf tree branch is not specified"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
if [ -z "${BASELINE_COMMIT}" ] || [ -z "${BPF_BASELINE_COMMIT}" ]; then
|
||||||
|
echo "Error: bpf or bpf-next baseline commits are not provided"
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
|
SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
|
||||||
BASELINE_COMMIT=${3-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
WORKDIR=$(pwd)
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
||||||
|
|
||||||
|
declare -A PATH_MAP
|
||||||
|
PATH_MAP=( \
|
||||||
|
[tools/lib/bpf]=src \
|
||||||
|
[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/btf.h]=include/uapi/linux/btf.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/netlink.h]=include/uapi/linux/netlink.h \
|
||||||
|
[tools/include/tools/libc_compat.h]=include/tools/libc_compat.h \
|
||||||
|
)
|
||||||
|
|
||||||
|
LIBBPF_PATHS="${!PATH_MAP[@]}"
|
||||||
|
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||||
|
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$'
|
||||||
|
|
||||||
|
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
||||||
|
for p in "${!PATH_MAP[@]}"; do
|
||||||
|
LIBBPF_TREE_FILTER+="git mv -kf ${p} __libbpf/${PATH_MAP[${p}]} && "$'\\\n'
|
||||||
|
done
|
||||||
|
LIBBPF_TREE_FILTER+="git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.c,.gitignore} >/dev/null"
|
||||||
|
|
||||||
|
cd_to()
|
||||||
|
{
|
||||||
|
cd ${WORKDIR} && cd "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output brief single-line commit description
|
||||||
|
# $1 - commit ref
|
||||||
|
commit_desc()
|
||||||
|
{
|
||||||
|
git log -n1 --pretty='%h ("%s")' $1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create commit single-line signature, which consists of:
|
||||||
|
# - full commit hash
|
||||||
|
# - author date in ISO8601 format
|
||||||
|
# - full commit body with newlines replaced with vertical bars (|)
|
||||||
|
# - shortstat appended at the end
|
||||||
|
# The idea is that this single-line signature is good enough to make final
|
||||||
|
# decision about whether two commits are the same, across different repos.
|
||||||
|
# $1 - commit ref
|
||||||
|
commit_signature()
|
||||||
|
{
|
||||||
|
git log -n1 --pretty='("%s")|%aI|%b' --shortstat $1 | tr '\n' '|'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate there are no non-empty merges (we can't handle them)
|
||||||
|
# $1 - baseline tag
|
||||||
|
# $2 - tip tag
|
||||||
|
validate_merges()
|
||||||
|
{
|
||||||
|
local baseline_tag=$1
|
||||||
|
local tip_tag=$2
|
||||||
|
local new_merges
|
||||||
|
local merge_change_cnt
|
||||||
|
local ignore_merge_resolutions
|
||||||
|
local desc
|
||||||
|
|
||||||
|
new_merges=$(git rev-list --merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||||
|
for new_merge in ${new_merges}; do
|
||||||
|
desc=$(commit_desc ${new_merge})
|
||||||
|
echo "MERGE: ${desc}"
|
||||||
|
merge_change_cnt=$(git show --format='' ${new_merge} | wc -l)
|
||||||
|
if ((${merge_change_cnt} > 0)); then
|
||||||
|
read -p "Merge '${desc}' is non-empty, which will cause conflicts! Do you want to proceed? [y/N]: " ignore_merge_resolutions
|
||||||
|
case "${ignore_merge_resolutions}" in
|
||||||
|
"y" | "Y")
|
||||||
|
echo "Skipping '${desc}'..."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cherry-pick commits touching libbpf-related files
|
||||||
|
# $1 - baseline_tag
|
||||||
|
# $2 - tip_tag
|
||||||
|
cherry_pick_commits()
|
||||||
|
{
|
||||||
|
local manual_mode=${MANUAL_MODE:-0}
|
||||||
|
local baseline_tag=$1
|
||||||
|
local tip_tag=$2
|
||||||
|
local new_commits
|
||||||
|
local signature
|
||||||
|
local should_skip
|
||||||
|
local synced_cnt
|
||||||
|
local manual_check
|
||||||
|
local libbpf_conflict_cnt
|
||||||
|
local desc
|
||||||
|
|
||||||
|
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||||
|
for new_commit in ${new_commits}; do
|
||||||
|
desc="$(commit_desc ${new_commit})"
|
||||||
|
signature="$(commit_signature ${new_commit})"
|
||||||
|
synced_cnt=$(grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | wc -l)
|
||||||
|
manual_check=0
|
||||||
|
if ((${synced_cnt} > 0)); then
|
||||||
|
# commit with the same subject is already in libbpf, but it's
|
||||||
|
# not 100% the same commit, so check with user
|
||||||
|
echo "Commit '${desc}' is synced into libbpf as:"
|
||||||
|
grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | \
|
||||||
|
cut -d'|' -f1 | sed -e 's/^/- /'
|
||||||
|
if ((${manual_mode} != 1 && ${synced_cnt} == 1)); then
|
||||||
|
echo "Skipping '${desc}' due to unique match..."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ((${synced_cnt} > 1)); then
|
||||||
|
echo "'${desc} matches multiple commits, please, double-check!"
|
||||||
|
manual_check=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if ((${manual_mode} == 1 || ${manual_check} == 1)); then
|
||||||
|
read -p "Do you want to skip '${desc}'? [y/N]: " should_skip
|
||||||
|
case "${should_skip}" in
|
||||||
|
"y" | "Y")
|
||||||
|
echo "Skipping '${desc}'..."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
# commit hasn't been synced into libbpf yet
|
||||||
|
echo "Picking '${desc}'..."
|
||||||
|
if ! git cherry-pick ${new_commit} &>/dev/null; then
|
||||||
|
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)
|
||||||
|
conflict_cnt=$(git diff --name-only | wc -l)
|
||||||
|
|
||||||
|
if ((${libbpf_conflict_cnt} == 0)); then
|
||||||
|
echo "Looks like only non-libbpf files have conflicts, ignoring..."
|
||||||
|
if ((${conflict_cnt} == 0)); then
|
||||||
|
echo "Empty cherry-pick, skipping it..."
|
||||||
|
git cherry-pick --abort
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
git add .
|
||||||
|
# GIT_EDITOR=true to avoid editor popping up to edit commit message
|
||||||
|
if ! GIT_EDITOR=true git cherry-pick --continue &>/dev/null; then
|
||||||
|
echo "Error! That still failed! Please resolve manually."
|
||||||
|
else
|
||||||
|
echo "Success! All cherry-pick conflicts were resolved for '${desc}'!"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cd_to ${LIBBPF_REPO}
|
||||||
|
GITHUB_ABS_DIR=$(pwd)
|
||||||
|
echo "Dumping existing libbpf commit signatures..."
|
||||||
|
for h in $(git log --pretty='%h' -n500); do
|
||||||
|
echo $h "$(commit_signature $h)" >> ${TMP_DIR}/libbpf_commits.txt
|
||||||
|
done
|
||||||
|
|
||||||
# Use current kernel repo HEAD as a source of patches
|
# Use current kernel repo HEAD as a source of patches
|
||||||
cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
|
LINUX_ABS_DIR=$(pwd)
|
||||||
TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
|
TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
|
||||||
TIP_COMMIT=$(git rev-parse HEAD)
|
TIP_COMMIT=$(git rev-parse HEAD)
|
||||||
|
BPF_TIP_COMMIT=$(git rev-parse ${BPF_BRANCH})
|
||||||
BASELINE_TAG=libbpf-baseline-${SUFFIX}
|
BASELINE_TAG=libbpf-baseline-${SUFFIX}
|
||||||
TIP_TAG=libbpf-tip-${SUFFIX}
|
TIP_TAG=libbpf-tip-${SUFFIX}
|
||||||
|
BPF_BASELINE_TAG=libbpf-bpf-baseline-${SUFFIX}
|
||||||
|
BPF_TIP_TAG=libbpf-bpf-tip-${SUFFIX}
|
||||||
VIEW_TAG=libbpf-view-${SUFFIX}
|
VIEW_TAG=libbpf-view-${SUFFIX}
|
||||||
LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
|
LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
|
||||||
|
|
||||||
@@ -43,75 +215,41 @@ SQUASH_BASE_TAG=libbpf-squash-base-${SUFFIX}
|
|||||||
SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
|
SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
|
||||||
SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
|
SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
|
||||||
|
|
||||||
echo "SUFFIX: ${SUFFIX}"
|
echo "WORKDIR: ${WORKDIR}"
|
||||||
echo "BASELINE COMMIT: $(git log --pretty=oneline --no-walk ${BASELINE_COMMIT})"
|
echo "LINUX REPO: ${LINUX_REPO}"
|
||||||
echo "TIP COMMIT: $(git log --pretty=oneline --no-walk ${TIP_COMMIT})"
|
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
||||||
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
echo "TEMP DIR: ${TMP_DIR}"
|
||||||
echo "BASELINE TAG: ${BASELINE_TAG}"
|
echo "SUFFIX: ${SUFFIX}"
|
||||||
echo "TIP TAG: ${TIP_TAG}"
|
echo "BASE COMMIT: '$(commit_desc ${BASELINE_COMMIT})'"
|
||||||
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
echo "TIP COMMIT: '$(commit_desc ${TIP_COMMIT})'"
|
||||||
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
echo "BPF BASE COMMIT: '$(commit_desc ${BPF_BASELINE_COMMIT})'"
|
||||||
echo "VIEW TAG: ${VIEW_TAG}"
|
echo "BPF TIP COMMIT: '$(commit_desc ${BPF_TIP_COMMIT})'"
|
||||||
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
||||||
|
echo "BASELINE TAG: ${BASELINE_TAG}"
|
||||||
TMP_DIR=$(mktemp -d)
|
echo "TIP TAG: ${TIP_TAG}"
|
||||||
echo "TEMP DIR: ${TMP_DIR}"
|
echo "BPF BASELINE TAG: ${BPF_BASELINE_TAG}"
|
||||||
echo "PATCHES+COVER: ${TMP_DIR}/patches"
|
echo "BPF TIP TAG: ${BPF_TIP_TAG}"
|
||||||
echo "PATCHSET: ${TMP_DIR}/patchset.patch"
|
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
||||||
|
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
||||||
|
echo "VIEW TAG: ${VIEW_TAG}"
|
||||||
|
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
||||||
|
echo "PATCHES: ${TMP_DIR}/patches"
|
||||||
|
|
||||||
git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
|
git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
|
||||||
git branch ${TIP_TAG} ${TIP_COMMIT}
|
git branch ${TIP_TAG} ${TIP_COMMIT}
|
||||||
|
git branch ${BPF_BASELINE_TAG} ${BPF_BASELINE_COMMIT}
|
||||||
|
git branch ${BPF_TIP_TAG} ${BPF_TIP_COMMIT}
|
||||||
git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
|
git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
|
||||||
git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
|
git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
|
||||||
|
|
||||||
|
# Validate there are no non-empty merges in bpf-next and bpf trees
|
||||||
|
validate_merges ${BASELINE_TAG} ${TIP_TAG}
|
||||||
|
validate_merges ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||||
|
|
||||||
# Cherry-pick new commits onto squashed baseline commit
|
# Cherry-pick new commits onto squashed baseline commit
|
||||||
LIBBPF_PATHS=(tools/lib/bpf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} tools/include/tools/libc_compat.h)
|
cherry_pick_commits ${BASELINE_TAG} ${TIP_TAG}
|
||||||
|
cherry_pick_commits ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||||
|
|
||||||
LIBBPF_NEW_MERGES=$(git rev-list --merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
|
||||||
for LIBBPF_NEW_MERGE in ${LIBBPF_NEW_MERGES}; do
|
|
||||||
printf "MERGE:\t" && git log --oneline -n1 ${LIBBPF_NEW_MERGE}
|
|
||||||
MERGE_CHANGES=$(git log --format='' -n1 ${LIBBPF_NEW_MERGE} | wc -l)
|
|
||||||
if ((${MERGE_CHANGES} > 0)); then
|
|
||||||
echo "Merge is non empty, aborting!.."
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
|
||||||
git log --oneline -n500 > ${TMP_DIR}/libbpf_commits.txt
|
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
|
||||||
|
|
||||||
LIBBPF_NEW_COMMITS=$(git rev-list --no-merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
|
||||||
for LIBBPF_NEW_COMMIT in ${LIBBPF_NEW_COMMITS}; do
|
|
||||||
echo "Checking commit '${LIBBPF_NEW_COMMIT}'"
|
|
||||||
SYNCED_COMMITS=$(grep -F "$(git log -n1 --pretty=format:%s ${LIBBPF_NEW_COMMIT})" ${TMP_DIR}/libbpf_commits.txt || echo "")
|
|
||||||
if [ -n "${SYNCED_COMMITS}" ]; then
|
|
||||||
# commit with the same subject is already in libbpf, but it's not 100% the same commit, so check with user
|
|
||||||
echo "Commit '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})' appears to be already synced into libbpf..."
|
|
||||||
echo "Corresponding libbpf commit(s):"
|
|
||||||
echo "${SYNCED_COMMITS}"
|
|
||||||
read -p "Do you want to skip it? [y/N]: " SHOULD_SKIP
|
|
||||||
case "${SHOULD_SKIP}" in
|
|
||||||
"y" | "Y")
|
|
||||||
echo "Skipping '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})'..."
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
# commit hasn't been synced into libbpf yet
|
|
||||||
if ! git cherry-pick ${LIBBPF_NEW_COMMIT}; then
|
|
||||||
read -p "Cherry-picking '$(git log --oneline -n1 ${LIBBPF_NEW_COMMIT})' failed, please fix manually and press <return> to proceed..."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
LIBBPF_TREE_FILTER=' \
|
|
||||||
mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && \
|
|
||||||
git mv -kf tools/lib/bpf __libbpf/src && \
|
|
||||||
git mv -kf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} \
|
|
||||||
__libbpf/include/uapi/linux && \
|
|
||||||
git mv -kf tools/include/tools/libc_compat.h __libbpf/include/tools && \
|
|
||||||
git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.cpp,.gitignore} \
|
|
||||||
'
|
|
||||||
# Move all libbpf files into __libbpf directory.
|
# Move all libbpf files into __libbpf directory.
|
||||||
git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
|
git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
|
||||||
# Make __libbpf a new root directory
|
# Make __libbpf a new root directory
|
||||||
@@ -126,59 +264,92 @@ 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 ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
||||||
# Now generate single-file patchset w/o cover to apply on top of libbpf repo
|
|
||||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --stdout > ${TMP_DIR}/patchset.patch
|
|
||||||
|
|
||||||
# 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 ${WORKDIR} && cd ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
git checkout -b ${LIBBPF_SYNC_TAG}
|
git checkout -b ${LIBBPF_SYNC_TAG}
|
||||||
git am --committer-date-is-author-date ${TMP_DIR}/patchset.patch
|
|
||||||
|
for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
||||||
|
if ! git am --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||||
|
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Generate bpf_helper_defs.h and commit, if anything changed
|
||||||
|
# restore Linux tip to use bpf_helpers_doc.py
|
||||||
|
cd_to ${LINUX_REPO}
|
||||||
|
git checkout ${TIP_TAG}
|
||||||
|
# re-generate bpf_helper_defs.h
|
||||||
|
cd_to ${LIBBPF_REPO}
|
||||||
|
"${LINUX_ABS_DIR}/scripts/bpf_helpers_doc.py" --header \
|
||||||
|
--file include/uapi/linux/bpf.h > src/bpf_helper_defs.h
|
||||||
|
# if anything changed, commit it
|
||||||
|
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
||||||
|
if ((${helpers_changes} == 1)); then
|
||||||
|
git add src/bpf_helper_defs.h
|
||||||
|
git commit -m "sync: auto-generate latest BPF helpers
|
||||||
|
|
||||||
|
Latest changes to BPF helper definitions.
|
||||||
|
" -- src/bpf_helper_defs.h
|
||||||
|
fi
|
||||||
|
|
||||||
# Use generated cover-letter as a template for "sync commit" with
|
# Use generated cover-letter as a template for "sync commit" with
|
||||||
# baseline and checkpoint commits from kernel repo (and leave summary
|
# baseline and checkpoint commits from kernel repo (and leave summary
|
||||||
# from cover letter intact, of course)
|
# from cover letter intact, of course)
|
||||||
echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
|
echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
|
||||||
|
echo ${BPF_TIP_COMMIT} > BPF-CHECKPOINT-COMMIT && \
|
||||||
git add CHECKPOINT-COMMIT && \
|
git add CHECKPOINT-COMMIT && \
|
||||||
|
git add BPF-CHECKPOINT-COMMIT && \
|
||||||
awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
|
awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
|
||||||
sed "s/\*\*\* BLURB HERE \*\*\*/\
|
sed "s/\*\*\* BLURB HERE \*\*\*/\
|
||||||
sync: latest libbpf changes from kernel\n\
|
sync: latest libbpf changes from kernel\n\
|
||||||
\n\
|
\n\
|
||||||
Syncing latest libbpf commits from kernel repository.\n\
|
Syncing latest libbpf commits from kernel repository.\n\
|
||||||
Baseline commit: ${BASELINE_COMMIT}\n\
|
Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
|
||||||
Checkpoint commit: ${TIP_COMMIT}/" | \
|
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
||||||
|
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
||||||
|
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
||||||
git commit --file=-
|
git commit --file=-
|
||||||
|
|
||||||
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
||||||
|
|
||||||
echo "Verifying Linux's and Github's libbpf state"
|
echo "Verifying Linux's and Github's libbpf state"
|
||||||
LIBBPF_VIEW_PATHS=(src include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} include/tools/libc_compat.h)
|
|
||||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf.cpp|\.gitignore)$'
|
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
LINUX_ABS_DIR=$(pwd)
|
|
||||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||||
git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
||||||
|
|
||||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
GITHUB_ABS_DIR=$(pwd)
|
|
||||||
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 ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||||
echo "Comparing file contents..."
|
echo "Comparing file contents..."
|
||||||
|
CONSISTENT=1
|
||||||
for F in $(cat ${TMP_DIR}/linux-view.ls); do
|
for F in $(cat ${TMP_DIR}/linux-view.ls); do
|
||||||
diff "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"
|
if ! diff -u "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"; then
|
||||||
|
echo "${LINUX_ABS_DIR}/${F} and ${GITHUB_ABS_DIR}/${F} are different!"
|
||||||
|
CONSISTENT=0
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
echo "Contents appear identical!"
|
if ((${CONSISTENT} == 1)); then
|
||||||
|
echo "Great! Content is identical!"
|
||||||
|
else
|
||||||
|
echo "Unfortunately, there are consistency problems!"
|
||||||
|
if ((${IGNORE_CONSISTENCY-0} != 1)); then
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Cleaning up..."
|
echo "Cleaning up..."
|
||||||
rm -r ${TMP_DIR}
|
rm -r ${TMP_DIR}
|
||||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
git checkout ${TIP_SYM_REF}
|
git checkout ${TIP_SYM_REF}
|
||||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
|
||||||
|
${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
||||||
|
|
||||||
cd ${WORKDIR}
|
cd_to .
|
||||||
echo "DONE."
|
echo "DONE."
|
||||||
|
|
||||||
|
|||||||
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
*.a
|
*.a
|
||||||
/libbpf.pc
|
/libbpf.pc
|
||||||
/libbpf.so*
|
/libbpf.so*
|
||||||
|
/staticobjs
|
||||||
|
/sharedobjs
|
||||||
|
|||||||
84
src/Makefile
84
src/Makefile
@@ -1,10 +1,9 @@
|
|||||||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
VERSION = 0
|
LIBBPF_VERSION := $(shell \
|
||||||
PATCHLEVEL = 0
|
grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | \
|
||||||
EXTRAVERSION = 3
|
sort -rV | head -n1 | cut -d'_' -f2)
|
||||||
|
LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
|
||||||
LIBBPF_VERSION = $(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)
|
|
||||||
|
|
||||||
TOPDIR = ..
|
TOPDIR = ..
|
||||||
|
|
||||||
@@ -16,15 +15,13 @@ ifneq ($(FEATURE_REALLOCARRAY),)
|
|||||||
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef BUILD_STATIC_ONLY
|
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||||
ALL_CFLAGS += -fPIC -fvisibility=hidden
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS ?= -g -O2 -Werror -Wall
|
CFLAGS ?= -g -O2 -Werror -Wall
|
||||||
ALL_CFLAGS += $(CFLAGS)
|
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||||
ALL_LDFLAGS += $(LDFLAGS)
|
ALL_LDFLAGS += $(LDFLAGS)
|
||||||
ifdef NO_PKG_CONFIG
|
ifdef NO_PKG_CONFIG
|
||||||
ALL_LDFLAGS += -lelf
|
ALL_LDFLAGS += -lelf -lz
|
||||||
else
|
else
|
||||||
PKG_CONFIG ?= pkg-config
|
PKG_CONFIG ?= pkg-config
|
||||||
ALL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libelf)
|
ALL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libelf)
|
||||||
@@ -32,22 +29,27 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
OBJDIR ?= .
|
OBJDIR ?= .
|
||||||
|
SHARED_OBJDIR := $(OBJDIR)/sharedobjs
|
||||||
OBJS := $(addprefix $(OBJDIR)/,bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||||
|
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
||||||
btf_dump.o hashmap.o)
|
btf_dump.o hashmap.o
|
||||||
|
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||||
|
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||||
|
|
||||||
LIBS := $(OBJDIR)/libbpf.a
|
STATIC_LIBS := $(OBJDIR)/libbpf.a
|
||||||
ifndef BUILD_STATIC_ONLY
|
ifndef BUILD_STATIC_ONLY
|
||||||
LIBS += $(OBJDIR)/libbpf.so \
|
SHARED_LIBS := $(OBJDIR)/libbpf.so \
|
||||||
$(OBJDIR)/libbpf.so.$(VERSION) \
|
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||||
VERSION_SCRIPT := libbpf.map
|
VERSION_SCRIPT := libbpf.map
|
||||||
endif
|
endif
|
||||||
|
|
||||||
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h
|
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h \
|
||||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,bpf.h bpf_common.h \
|
bpf_helpers.h bpf_helper_defs.h bpf_tracing.h \
|
||||||
btf.h)
|
bpf_endian.h bpf_core_read.h libbpf_common.h
|
||||||
|
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
||||||
|
bpf.h bpf_common.h btf.h)
|
||||||
|
|
||||||
PC_FILE := $(OBJDIR)/libbpf.pc
|
PC_FILE := $(OBJDIR)/libbpf.pc
|
||||||
|
|
||||||
@@ -66,21 +68,23 @@ LIBDIR ?= $(PREFIX)/$(LIBSUBDIR)
|
|||||||
INCLUDEDIR ?= $(PREFIX)/include
|
INCLUDEDIR ?= $(PREFIX)/include
|
||||||
UAPIDIR ?= $(PREFIX)/include
|
UAPIDIR ?= $(PREFIX)/include
|
||||||
|
|
||||||
all: $(LIBS) $(PC_FILE)
|
TAGS_PROG := $(if $(shell which etags 2>/dev/null),etags,ctags)
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.a: $(OBJS)
|
all: $(STATIC_LIBS) $(SHARED_LIBS) $(PC_FILE)
|
||||||
|
|
||||||
|
$(OBJDIR)/libbpf.a: $(STATIC_OBJS)
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(VERSION)
|
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION)
|
||||||
ln -sf $(^F) $@
|
ln -sf $(^F) $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so.$(VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||||
ln -sf $(^F) $@
|
ln -sf $(^F) $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(OBJS)
|
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
|
||||||
$(CC) -shared $(ALL_LDFLAGS) -Wl,--version-script=$(VERSION_SCRIPT) \
|
$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||||
-Wl,-soname,libbpf.so.$(VERSION) \
|
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||||
$^ -o $@
|
$^ $(ALL_LDFLAGS) -o $@
|
||||||
|
|
||||||
$(OBJDIR)/libbpf.pc:
|
$(OBJDIR)/libbpf.pc:
|
||||||
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||||
@@ -88,9 +92,18 @@ $(OBJDIR)/libbpf.pc:
|
|||||||
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
||||||
< libbpf.pc.template > $@
|
< libbpf.pc.template > $@
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.c
|
$(STATIC_OBJDIR):
|
||||||
|
mkdir -p $(STATIC_OBJDIR)
|
||||||
|
|
||||||
|
$(SHARED_OBJDIR):
|
||||||
|
mkdir -p $(SHARED_OBJDIR)
|
||||||
|
|
||||||
|
$(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
|
||||||
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
|
||||||
|
$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
||||||
define do_install
|
define do_install
|
||||||
if [ ! -d '$(DESTDIR)$2' ]; then \
|
if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||||
@@ -107,7 +120,7 @@ define do_s_install
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
install: all install_headers install_pkgconfig
|
install: all install_headers install_pkgconfig
|
||||||
$(call do_s_install,$(LIBS),$(LIBDIR))
|
$(call do_s_install,$(STATIC_LIBS) $(SHARED_LIBS),$(LIBDIR))
|
||||||
|
|
||||||
install_headers:
|
install_headers:
|
||||||
$(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
|
$(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
|
||||||
@@ -121,4 +134,13 @@ install_pkgconfig: $(PC_FILE)
|
|||||||
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a *.so *.so.* *.pc
|
rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
|
||||||
|
|
||||||
|
.PHONY: cscope tags
|
||||||
|
cscope:
|
||||||
|
ls *.c *.h > cscope.files
|
||||||
|
cscope -b -q -f cscope.out
|
||||||
|
|
||||||
|
tags:
|
||||||
|
rm -f TAGS tags
|
||||||
|
ls *.c *.h | xargs $(TAGS_PROG) -a
|
||||||
|
|||||||
122
src/bpf.c
122
src/bpf.c
@@ -32,6 +32,9 @@
|
|||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When building perf, unistd.h is overridden. __NR_bpf is
|
* When building perf, unistd.h is overridden. __NR_bpf is
|
||||||
* required to be defined explicitly.
|
* required to be defined explicitly.
|
||||||
@@ -95,7 +98,11 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
|||||||
attr.btf_key_type_id = create_attr->btf_key_type_id;
|
attr.btf_key_type_id = create_attr->btf_key_type_id;
|
||||||
attr.btf_value_type_id = create_attr->btf_value_type_id;
|
attr.btf_value_type_id = create_attr->btf_value_type_id;
|
||||||
attr.map_ifindex = create_attr->map_ifindex;
|
attr.map_ifindex = create_attr->map_ifindex;
|
||||||
attr.inner_map_fd = create_attr->inner_map_fd;
|
if (attr.map_type == BPF_MAP_TYPE_STRUCT_OPS)
|
||||||
|
attr.btf_vmlinux_value_type_id =
|
||||||
|
create_attr->btf_vmlinux_value_type_id;
|
||||||
|
else
|
||||||
|
attr.inner_map_fd = create_attr->inner_map_fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||||
}
|
}
|
||||||
@@ -189,7 +196,7 @@ static void *
|
|||||||
alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
||||||
__u32 actual_rec_size, __u32 expected_rec_size)
|
__u32 actual_rec_size, __u32 expected_rec_size)
|
||||||
{
|
{
|
||||||
__u64 info_len = actual_rec_size * cnt;
|
__u64 info_len = (__u64)actual_rec_size * cnt;
|
||||||
void *info, *nrecord;
|
void *info, *nrecord;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -228,6 +235,16 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.prog_type = load_attr->prog_type;
|
attr.prog_type = load_attr->prog_type;
|
||||||
attr.expected_attach_type = load_attr->expected_attach_type;
|
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||||
|
if (attr.prog_type == BPF_PROG_TYPE_STRUCT_OPS) {
|
||||||
|
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||||
|
} else if (attr.prog_type == BPF_PROG_TYPE_TRACING ||
|
||||||
|
attr.prog_type == BPF_PROG_TYPE_EXT) {
|
||||||
|
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||||
|
attr.attach_prog_fd = load_attr->attach_prog_fd;
|
||||||
|
} else {
|
||||||
|
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||||
|
attr.kern_version = load_attr->kern_version;
|
||||||
|
}
|
||||||
attr.insn_cnt = (__u32)load_attr->insns_cnt;
|
attr.insn_cnt = (__u32)load_attr->insns_cnt;
|
||||||
attr.insns = ptr_to_u64(load_attr->insns);
|
attr.insns = ptr_to_u64(load_attr->insns);
|
||||||
attr.license = ptr_to_u64(load_attr->license);
|
attr.license = ptr_to_u64(load_attr->license);
|
||||||
@@ -241,8 +258,6 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
attr.log_size = 0;
|
attr.log_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.kern_version = load_attr->kern_version;
|
|
||||||
attr.prog_ifindex = load_attr->prog_ifindex;
|
|
||||||
attr.prog_btf_fd = load_attr->prog_btf_fd;
|
attr.prog_btf_fd = load_attr->prog_btf_fd;
|
||||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||||
attr.func_info_cnt = load_attr->func_info_cnt;
|
attr.func_info_cnt = load_attr->func_info_cnt;
|
||||||
@@ -438,6 +453,64 @@ int bpf_map_freeze(int fd)
|
|||||||
return sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
return sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
||||||
|
void *out_batch, void *keys, void *values,
|
||||||
|
__u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts)
|
||||||
|
{
|
||||||
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, bpf_map_batch_opts))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.batch.map_fd = fd;
|
||||||
|
attr.batch.in_batch = ptr_to_u64(in_batch);
|
||||||
|
attr.batch.out_batch = ptr_to_u64(out_batch);
|
||||||
|
attr.batch.keys = ptr_to_u64(keys);
|
||||||
|
attr.batch.values = ptr_to_u64(values);
|
||||||
|
attr.batch.count = *count;
|
||||||
|
attr.batch.elem_flags = OPTS_GET(opts, elem_flags, 0);
|
||||||
|
attr.batch.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
|
ret = sys_bpf(cmd, &attr, sizeof(attr));
|
||||||
|
*count = attr.batch.count;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_delete_batch(int fd, void *keys, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts)
|
||||||
|
{
|
||||||
|
return bpf_map_batch_common(BPF_MAP_DELETE_BATCH, fd, NULL,
|
||||||
|
NULL, keys, NULL, count, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch, void *keys,
|
||||||
|
void *values, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts)
|
||||||
|
{
|
||||||
|
return bpf_map_batch_common(BPF_MAP_LOOKUP_BATCH, fd, in_batch,
|
||||||
|
out_batch, keys, values, count, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_lookup_and_delete_batch(int fd, void *in_batch, void *out_batch,
|
||||||
|
void *keys, void *values, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts)
|
||||||
|
{
|
||||||
|
return bpf_map_batch_common(BPF_MAP_LOOKUP_AND_DELETE_BATCH,
|
||||||
|
fd, in_batch, out_batch, keys, values,
|
||||||
|
count, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_update_batch(int fd, void *keys, void *values, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts)
|
||||||
|
{
|
||||||
|
return bpf_map_batch_common(BPF_MAP_UPDATE_BATCH, fd, NULL, NULL,
|
||||||
|
keys, values, count, opts);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_obj_pin(int fd, const char *pathname)
|
int bpf_obj_pin(int fd, const char *pathname)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
@@ -461,14 +534,29 @@ int bpf_obj_get(const char *pathname)
|
|||||||
|
|
||||||
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
DECLARE_LIBBPF_OPTS(bpf_prog_attach_opts, opts,
|
||||||
|
.flags = flags,
|
||||||
|
);
|
||||||
|
|
||||||
|
return bpf_prog_attach_xattr(prog_fd, target_fd, type, &opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_prog_attach_xattr(int prog_fd, int target_fd,
|
||||||
|
enum bpf_attach_type type,
|
||||||
|
const struct bpf_prog_attach_opts *opts)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
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 = flags;
|
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
||||||
|
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
|
return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
|
||||||
}
|
}
|
||||||
@@ -568,7 +656,7 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
int err;
|
int err;
|
||||||
@@ -576,26 +664,26 @@ int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
|||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.start_id = start_id;
|
attr.start_id = start_id;
|
||||||
|
|
||||||
err = sys_bpf(BPF_PROG_GET_NEXT_ID, &attr, sizeof(attr));
|
err = sys_bpf(cmd, &attr, sizeof(attr));
|
||||||
if (!err)
|
if (!err)
|
||||||
*next_id = attr.next_id;
|
*next_id = attr.next_id;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
|
{
|
||||||
|
return bpf_obj_get_next_id(start_id, next_id, BPF_PROG_GET_NEXT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_map_get_next_id(__u32 start_id, __u32 *next_id)
|
int bpf_map_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
return bpf_obj_get_next_id(start_id, next_id, BPF_MAP_GET_NEXT_ID);
|
||||||
int err;
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
attr.start_id = start_id;
|
{
|
||||||
|
return bpf_obj_get_next_id(start_id, next_id, BPF_BTF_GET_NEXT_ID);
|
||||||
err = sys_bpf(BPF_MAP_GET_NEXT_ID, &attr, sizeof(attr));
|
|
||||||
if (!err)
|
|
||||||
*next_id = attr.next_id;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_fd_by_id(__u32 id)
|
int bpf_prog_get_fd_by_id(__u32 id)
|
||||||
|
|||||||
55
src/bpf.h
55
src/bpf.h
@@ -28,14 +28,12 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "libbpf_common.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LIBBPF_API
|
|
||||||
#define LIBBPF_API __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct bpf_create_map_attr {
|
struct bpf_create_map_attr {
|
||||||
const char *name;
|
const char *name;
|
||||||
enum bpf_map_type map_type;
|
enum bpf_map_type map_type;
|
||||||
@@ -48,7 +46,10 @@ struct bpf_create_map_attr {
|
|||||||
__u32 btf_key_type_id;
|
__u32 btf_key_type_id;
|
||||||
__u32 btf_value_type_id;
|
__u32 btf_value_type_id;
|
||||||
__u32 map_ifindex;
|
__u32 map_ifindex;
|
||||||
__u32 inner_map_fd;
|
union {
|
||||||
|
__u32 inner_map_fd;
|
||||||
|
__u32 btf_vmlinux_value_type_id;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBBPF_API int
|
LIBBPF_API int
|
||||||
@@ -77,8 +78,14 @@ struct bpf_load_program_attr {
|
|||||||
const struct bpf_insn *insns;
|
const struct bpf_insn *insns;
|
||||||
size_t insns_cnt;
|
size_t insns_cnt;
|
||||||
const char *license;
|
const char *license;
|
||||||
__u32 kern_version;
|
union {
|
||||||
__u32 prog_ifindex;
|
__u32 kern_version;
|
||||||
|
__u32 attach_prog_fd;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
__u32 prog_ifindex;
|
||||||
|
__u32 attach_btf_id;
|
||||||
|
};
|
||||||
__u32 prog_btf_fd;
|
__u32 prog_btf_fd;
|
||||||
__u32 func_info_rec_size;
|
__u32 func_info_rec_size;
|
||||||
const void *func_info;
|
const void *func_info;
|
||||||
@@ -120,10 +127,43 @@ LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
|
|||||||
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
|
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
|
||||||
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
||||||
LIBBPF_API int bpf_map_freeze(int fd);
|
LIBBPF_API int bpf_map_freeze(int fd);
|
||||||
|
|
||||||
|
struct bpf_map_batch_opts {
|
||||||
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
__u64 elem_flags;
|
||||||
|
__u64 flags;
|
||||||
|
};
|
||||||
|
#define bpf_map_batch_opts__last_field flags
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_map_delete_batch(int fd, void *keys,
|
||||||
|
__u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
LIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch,
|
||||||
|
void *keys, void *values, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
LIBBPF_API int bpf_map_lookup_and_delete_batch(int fd, void *in_batch,
|
||||||
|
void *out_batch, void *keys,
|
||||||
|
void *values, __u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
LIBBPF_API int bpf_map_update_batch(int fd, void *keys, void *values,
|
||||||
|
__u32 *count,
|
||||||
|
const struct bpf_map_batch_opts *opts);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
struct bpf_prog_attach_opts {
|
||||||
|
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||||
|
unsigned int flags;
|
||||||
|
int replace_prog_fd;
|
||||||
|
};
|
||||||
|
#define bpf_prog_attach_opts__last_field replace_prog_fd
|
||||||
|
|
||||||
LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
||||||
enum bpf_attach_type type, unsigned int flags);
|
enum bpf_attach_type type, unsigned int flags);
|
||||||
|
LIBBPF_API int bpf_prog_attach_xattr(int prog_fd, int attachable_fd,
|
||||||
|
enum bpf_attach_type type,
|
||||||
|
const struct bpf_prog_attach_opts *opts);
|
||||||
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||||
enum bpf_attach_type type);
|
enum bpf_attach_type type);
|
||||||
@@ -156,6 +196,7 @@ LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
|||||||
__u32 *retval, __u32 *duration);
|
__u32 *retval, __u32 *duration);
|
||||||
LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
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_prog_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_prog_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(__u32 id);
|
||||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||||
|
|||||||
263
src/bpf_core_read.h
Normal file
263
src/bpf_core_read.h
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
#ifndef __BPF_CORE_READ_H__
|
||||||
|
#define __BPF_CORE_READ_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum bpf_field_info_kind is passed as a second argument into
|
||||||
|
* __builtin_preserve_field_info() built-in to get a specific aspect of
|
||||||
|
* a field, captured as a first argument. __builtin_preserve_field_info(field,
|
||||||
|
* info_kind) returns __u32 integer and produces BTF field relocation, which
|
||||||
|
* is understood and processed by libbpf during BPF object loading. See
|
||||||
|
* selftests/bpf for examples.
|
||||||
|
*/
|
||||||
|
enum bpf_field_info_kind {
|
||||||
|
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
||||||
|
BPF_FIELD_BYTE_SIZE = 1,
|
||||||
|
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
||||||
|
BPF_FIELD_SIGNED = 3,
|
||||||
|
BPF_FIELD_LSHIFT_U64 = 4,
|
||||||
|
BPF_FIELD_RSHIFT_U64 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define __CORE_RELO(src, field, info) \
|
||||||
|
__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
|
||||||
|
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||||
|
bpf_probe_read((void *)dst, \
|
||||||
|
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||||
|
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||||
|
#else
|
||||||
|
/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so
|
||||||
|
* for big-endian we need to adjust destination pointer accordingly, based on
|
||||||
|
* field byte size
|
||||||
|
*/
|
||||||
|
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||||
|
bpf_probe_read((void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \
|
||||||
|
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||||
|
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract bitfield, identified by s->field, and return its value as u64.
|
||||||
|
* All this is done in relocatable manner, so bitfield changes such as
|
||||||
|
* signedness, bit size, offset changes, this will be handled automatically.
|
||||||
|
* This version of macro is using bpf_probe_read() to read underlying integer
|
||||||
|
* storage. Macro functions as an expression and its return type is
|
||||||
|
* bpf_probe_read()'s return value: 0, on success, <0 on error.
|
||||||
|
*/
|
||||||
|
#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({ \
|
||||||
|
unsigned long long val = 0; \
|
||||||
|
\
|
||||||
|
__CORE_BITFIELD_PROBE_READ(&val, s, field); \
|
||||||
|
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
||||||
|
if (__CORE_RELO(s, field, SIGNED)) \
|
||||||
|
val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \
|
||||||
|
else \
|
||||||
|
val = val >> __CORE_RELO(s, field, RSHIFT_U64); \
|
||||||
|
val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract bitfield, identified by s->field, and return its value as u64.
|
||||||
|
* This version of macro is using direct memory reads and should be used from
|
||||||
|
* BPF program types that support such functionality (e.g., typed raw
|
||||||
|
* tracepoints).
|
||||||
|
*/
|
||||||
|
#define BPF_CORE_READ_BITFIELD(s, field) ({ \
|
||||||
|
const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
||||||
|
unsigned long long val; \
|
||||||
|
\
|
||||||
|
switch (__CORE_RELO(s, field, BYTE_SIZE)) { \
|
||||||
|
case 1: val = *(const unsigned char *)p; \
|
||||||
|
case 2: val = *(const unsigned short *)p; \
|
||||||
|
case 4: val = *(const unsigned int *)p; \
|
||||||
|
case 8: val = *(const unsigned long long *)p; \
|
||||||
|
} \
|
||||||
|
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
||||||
|
if (__CORE_RELO(s, field, SIGNED)) \
|
||||||
|
val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \
|
||||||
|
else \
|
||||||
|
val = val >> __CORE_RELO(s, field, RSHIFT_U64); \
|
||||||
|
val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience macro to check that field actually exists in target kernel's.
|
||||||
|
* Returns:
|
||||||
|
* 1, if matching field is present in target kernel;
|
||||||
|
* 0, if no matching field found.
|
||||||
|
*/
|
||||||
|
#define bpf_core_field_exists(field) \
|
||||||
|
__builtin_preserve_field_info(field, BPF_FIELD_EXISTS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience macro to get byte size of a field. Works for integers,
|
||||||
|
* struct/unions, pointers, arrays, and enums.
|
||||||
|
*/
|
||||||
|
#define bpf_core_field_size(field) \
|
||||||
|
__builtin_preserve_field_info(field, BPF_FIELD_BYTE_SIZE)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_core_read() abstracts away bpf_probe_read() call and captures offset
|
||||||
|
* relocation for source address using __builtin_preserve_access_index()
|
||||||
|
* built-in, provided by Clang.
|
||||||
|
*
|
||||||
|
* __builtin_preserve_access_index() takes as an argument an expression of
|
||||||
|
* taking an address of a field within struct/union. It makes compiler emit
|
||||||
|
* a relocation, which records BTF type ID describing root struct/union and an
|
||||||
|
* accessor string which describes exact embedded field that was used to take
|
||||||
|
* an address. See detailed description of this relocation format and
|
||||||
|
* semantics in comments to struct bpf_field_reloc in libbpf_internal.h.
|
||||||
|
*
|
||||||
|
* This relocation allows libbpf to adjust BPF instruction to use correct
|
||||||
|
* actual field offset, based on target kernel BTF type that matches original
|
||||||
|
* (local) BTF, used to record relocation.
|
||||||
|
*/
|
||||||
|
#define bpf_core_read(dst, sz, src) \
|
||||||
|
bpf_probe_read(dst, sz, \
|
||||||
|
(const void *)__builtin_preserve_access_index(src))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()
|
||||||
|
* additionally emitting BPF CO-RE field relocation for specified source
|
||||||
|
* argument.
|
||||||
|
*/
|
||||||
|
#define bpf_core_read_str(dst, sz, src) \
|
||||||
|
bpf_probe_read_str(dst, sz, \
|
||||||
|
(const void *)__builtin_preserve_access_index(src))
|
||||||
|
|
||||||
|
#define ___concat(a, b) a ## b
|
||||||
|
#define ___apply(fn, n) ___concat(fn, n)
|
||||||
|
#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return number of provided arguments; used for switch-based variadic macro
|
||||||
|
* definitions (see ___last, ___arrow, etc below)
|
||||||
|
*/
|
||||||
|
#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
/*
|
||||||
|
* return 0 if no arguments are passed, N - otherwise; used for
|
||||||
|
* recursively-defined macros to specify termination (0) case, and generic
|
||||||
|
* (N) case (e.g., ___read_ptrs, ___core_read)
|
||||||
|
*/
|
||||||
|
#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)
|
||||||
|
|
||||||
|
#define ___last1(x) x
|
||||||
|
#define ___last2(a, x) x
|
||||||
|
#define ___last3(a, b, x) x
|
||||||
|
#define ___last4(a, b, c, x) x
|
||||||
|
#define ___last5(a, b, c, d, x) x
|
||||||
|
#define ___last6(a, b, c, d, e, x) x
|
||||||
|
#define ___last7(a, b, c, d, e, f, x) x
|
||||||
|
#define ___last8(a, b, c, d, e, f, g, x) x
|
||||||
|
#define ___last9(a, b, c, d, e, f, g, h, x) x
|
||||||
|
#define ___last10(a, b, c, d, e, f, g, h, i, x) x
|
||||||
|
#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define ___nolast2(a, _) a
|
||||||
|
#define ___nolast3(a, b, _) a, b
|
||||||
|
#define ___nolast4(a, b, c, _) a, b, c
|
||||||
|
#define ___nolast5(a, b, c, d, _) a, b, c, d
|
||||||
|
#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e
|
||||||
|
#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f
|
||||||
|
#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g
|
||||||
|
#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h
|
||||||
|
#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i
|
||||||
|
#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define ___arrow1(a) a
|
||||||
|
#define ___arrow2(a, b) a->b
|
||||||
|
#define ___arrow3(a, b, c) a->b->c
|
||||||
|
#define ___arrow4(a, b, c, d) a->b->c->d
|
||||||
|
#define ___arrow5(a, b, c, d, e) a->b->c->d->e
|
||||||
|
#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f
|
||||||
|
#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g
|
||||||
|
#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h
|
||||||
|
#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i
|
||||||
|
#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j
|
||||||
|
#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define ___type(...) typeof(___arrow(__VA_ARGS__))
|
||||||
|
|
||||||
|
#define ___read(read_fn, dst, src_type, src, accessor) \
|
||||||
|
read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
|
||||||
|
|
||||||
|
/* "recursively" read a sequence of inner pointers using local __t var */
|
||||||
|
#define ___rd_first(src, a) ___read(bpf_core_read, &__t, ___type(src), src, a);
|
||||||
|
#define ___rd_last(...) \
|
||||||
|
___read(bpf_core_read, &__t, \
|
||||||
|
___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
|
||||||
|
#define ___rd_p1(...) const void *__t; ___rd_first(__VA_ARGS__)
|
||||||
|
#define ___rd_p2(...) ___rd_p1(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p3(...) ___rd_p2(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p4(...) ___rd_p3(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p5(...) ___rd_p4(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p6(...) ___rd_p5(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p7(...) ___rd_p6(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p8(...) ___rd_p7(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___rd_p9(...) ___rd_p8(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||||
|
#define ___read_ptrs(src, ...) \
|
||||||
|
___apply(___rd_p, ___narg(__VA_ARGS__))(src, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define ___core_read0(fn, dst, src, a) \
|
||||||
|
___read(fn, dst, ___type(src), src, a);
|
||||||
|
#define ___core_readN(fn, dst, src, ...) \
|
||||||
|
___read_ptrs(src, ___nolast(__VA_ARGS__)) \
|
||||||
|
___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \
|
||||||
|
___last(__VA_ARGS__));
|
||||||
|
#define ___core_read(fn, dst, src, a, ...) \
|
||||||
|
___apply(___core_read, ___empty(__VA_ARGS__))(fn, dst, \
|
||||||
|
src, a, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BPF_CORE_READ_INTO() is a more performance-conscious variant of
|
||||||
|
* BPF_CORE_READ(), in which final field is read into user-provided storage.
|
||||||
|
* See BPF_CORE_READ() below for more details on general usage.
|
||||||
|
*/
|
||||||
|
#define BPF_CORE_READ_INTO(dst, src, a, ...) \
|
||||||
|
({ \
|
||||||
|
___core_read(bpf_core_read, dst, src, a, ##__VA_ARGS__) \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BPF_CORE_READ_STR_INTO() does same "pointer chasing" as
|
||||||
|
* BPF_CORE_READ() for intermediate pointers, but then executes (and returns
|
||||||
|
* corresponding error code) bpf_core_read_str() for final string read.
|
||||||
|
*/
|
||||||
|
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \
|
||||||
|
({ \
|
||||||
|
___core_read(bpf_core_read_str, dst, src, a, ##__VA_ARGS__) \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially
|
||||||
|
* when there are few pointer chasing steps.
|
||||||
|
* E.g., what in non-BPF world (or in BPF w/ BCC) would be something like:
|
||||||
|
* int x = s->a.b.c->d.e->f->g;
|
||||||
|
* can be succinctly achieved using BPF_CORE_READ as:
|
||||||
|
* int x = BPF_CORE_READ(s, a.b.c, d.e, f, g);
|
||||||
|
*
|
||||||
|
* BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF
|
||||||
|
* CO-RE relocatable bpf_probe_read() wrapper) calls, logically equivalent to:
|
||||||
|
* 1. const void *__t = s->a.b.c;
|
||||||
|
* 2. __t = __t->d.e;
|
||||||
|
* 3. __t = __t->f;
|
||||||
|
* 4. return __t->g;
|
||||||
|
*
|
||||||
|
* Equivalence is logical, because there is a heavy type casting/preservation
|
||||||
|
* involved, as well as all the reads are happening through bpf_probe_read()
|
||||||
|
* calls using __builtin_preserve_access_index() to emit CO-RE relocations.
|
||||||
|
*
|
||||||
|
* N.B. Only up to 9 "field accessors" are supported, which should be more
|
||||||
|
* than enough for any practical purpose.
|
||||||
|
*/
|
||||||
|
#define BPF_CORE_READ(src, a, ...) \
|
||||||
|
({ \
|
||||||
|
___type(src, a, ##__VA_ARGS__) __r; \
|
||||||
|
BPF_CORE_READ_INTO(&__r, src, a, ##__VA_ARGS__); \
|
||||||
|
__r; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
72
src/bpf_endian.h
Normal file
72
src/bpf_endian.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
#ifndef __BPF_ENDIAN__
|
||||||
|
#define __BPF_ENDIAN__
|
||||||
|
|
||||||
|
#include <linux/stddef.h>
|
||||||
|
#include <linux/swab.h>
|
||||||
|
|
||||||
|
/* LLVM's BPF target selects the endianness of the CPU
|
||||||
|
* it compiles on, or the user specifies (bpfel/bpfeb),
|
||||||
|
* respectively. The used __BYTE_ORDER__ is defined by
|
||||||
|
* the compiler, we cannot rely on __BYTE_ORDER from
|
||||||
|
* libc headers, since it doesn't reflect the actual
|
||||||
|
* requested byte order.
|
||||||
|
*
|
||||||
|
* Note, LLVM's BPF target has different __builtin_bswapX()
|
||||||
|
* semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
|
||||||
|
* in bpfel and bpfeb case, which means below, that we map
|
||||||
|
* to cpu_to_be16(). We could use it unconditionally in BPF
|
||||||
|
* case, but better not rely on it, so that this header here
|
||||||
|
* can be used from application and BPF program side, which
|
||||||
|
* use different targets.
|
||||||
|
*/
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
# define __bpf_ntohs(x) __builtin_bswap16(x)
|
||||||
|
# define __bpf_htons(x) __builtin_bswap16(x)
|
||||||
|
# define __bpf_constant_ntohs(x) ___constant_swab16(x)
|
||||||
|
# define __bpf_constant_htons(x) ___constant_swab16(x)
|
||||||
|
# define __bpf_ntohl(x) __builtin_bswap32(x)
|
||||||
|
# define __bpf_htonl(x) __builtin_bswap32(x)
|
||||||
|
# define __bpf_constant_ntohl(x) ___constant_swab32(x)
|
||||||
|
# define __bpf_constant_htonl(x) ___constant_swab32(x)
|
||||||
|
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
|
||||||
|
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
|
||||||
|
# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x)
|
||||||
|
# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x)
|
||||||
|
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
# define __bpf_ntohs(x) (x)
|
||||||
|
# define __bpf_htons(x) (x)
|
||||||
|
# define __bpf_constant_ntohs(x) (x)
|
||||||
|
# define __bpf_constant_htons(x) (x)
|
||||||
|
# define __bpf_ntohl(x) (x)
|
||||||
|
# define __bpf_htonl(x) (x)
|
||||||
|
# define __bpf_constant_ntohl(x) (x)
|
||||||
|
# define __bpf_constant_htonl(x) (x)
|
||||||
|
# define __bpf_be64_to_cpu(x) (x)
|
||||||
|
# define __bpf_cpu_to_be64(x) (x)
|
||||||
|
# define __bpf_constant_be64_to_cpu(x) (x)
|
||||||
|
# define __bpf_constant_cpu_to_be64(x) (x)
|
||||||
|
#else
|
||||||
|
# error "Fix your compiler's __BYTE_ORDER__?!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define bpf_htons(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_htons(x) : __bpf_htons(x))
|
||||||
|
#define bpf_ntohs(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_ntohs(x) : __bpf_ntohs(x))
|
||||||
|
#define bpf_htonl(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_htonl(x) : __bpf_htonl(x))
|
||||||
|
#define bpf_ntohl(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_ntohl(x) : __bpf_ntohl(x))
|
||||||
|
#define bpf_cpu_to_be64(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
|
||||||
|
#define bpf_be64_to_cpu(x) \
|
||||||
|
(__builtin_constant_p(x) ? \
|
||||||
|
__bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
|
||||||
|
|
||||||
|
#endif /* __BPF_ENDIAN__ */
|
||||||
2799
src/bpf_helper_defs.h
Normal file
2799
src/bpf_helper_defs.h
Normal file
File diff suppressed because it is too large
Load Diff
58
src/bpf_helpers.h
Normal file
58
src/bpf_helpers.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
#ifndef __BPF_HELPERS__
|
||||||
|
#define __BPF_HELPERS__
|
||||||
|
|
||||||
|
#include "bpf_helper_defs.h"
|
||||||
|
|
||||||
|
#define __uint(name, val) int (*name)[val]
|
||||||
|
#define __type(name, val) typeof(val) *name
|
||||||
|
|
||||||
|
/* Helper macro to print out debug messages */
|
||||||
|
#define bpf_printk(fmt, ...) \
|
||||||
|
({ \
|
||||||
|
char ____fmt[] = fmt; \
|
||||||
|
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||||
|
##__VA_ARGS__); \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macro to place programs, maps, license in
|
||||||
|
* different sections in elf_bpf file. Section names
|
||||||
|
* are interpreted by elf_bpf loader
|
||||||
|
*/
|
||||||
|
#define SEC(NAME) __attribute__((section(NAME), used))
|
||||||
|
|
||||||
|
#ifndef __always_inline
|
||||||
|
#define __always_inline __attribute__((always_inline))
|
||||||
|
#endif
|
||||||
|
#ifndef __weak
|
||||||
|
#define __weak __attribute__((weak))
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum libbpf_pin_type {
|
||||||
|
LIBBPF_PIN_NONE,
|
||||||
|
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
|
||||||
|
LIBBPF_PIN_BY_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum libbpf_tristate {
|
||||||
|
TRI_NO = 0,
|
||||||
|
TRI_YES = 1,
|
||||||
|
TRI_MODULE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define __kconfig __attribute__((section(".kconfig")))
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
struct bpf_prog_linfo {
|
struct bpf_prog_linfo {
|
||||||
void *raw_linfo;
|
void *raw_linfo;
|
||||||
void *raw_jited_linfo;
|
void *raw_jited_linfo;
|
||||||
@@ -101,6 +104,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
{
|
{
|
||||||
struct bpf_prog_linfo *prog_linfo;
|
struct bpf_prog_linfo *prog_linfo;
|
||||||
__u32 nr_linfo, nr_jited_func;
|
__u32 nr_linfo, nr_jited_func;
|
||||||
|
__u64 data_sz;
|
||||||
|
|
||||||
nr_linfo = info->nr_line_info;
|
nr_linfo = info->nr_line_info;
|
||||||
|
|
||||||
@@ -122,11 +126,11 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
/* Copy xlated line_info */
|
/* Copy xlated line_info */
|
||||||
prog_linfo->nr_linfo = nr_linfo;
|
prog_linfo->nr_linfo = nr_linfo;
|
||||||
prog_linfo->rec_size = info->line_info_rec_size;
|
prog_linfo->rec_size = info->line_info_rec_size;
|
||||||
prog_linfo->raw_linfo = malloc(nr_linfo * prog_linfo->rec_size);
|
data_sz = (__u64)nr_linfo * prog_linfo->rec_size;
|
||||||
|
prog_linfo->raw_linfo = malloc(data_sz);
|
||||||
if (!prog_linfo->raw_linfo)
|
if (!prog_linfo->raw_linfo)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info,
|
memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, data_sz);
|
||||||
nr_linfo * prog_linfo->rec_size);
|
|
||||||
|
|
||||||
nr_jited_func = info->nr_jited_ksyms;
|
nr_jited_func = info->nr_jited_ksyms;
|
||||||
if (!nr_jited_func ||
|
if (!nr_jited_func ||
|
||||||
@@ -142,13 +146,12 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
/* Copy jited_line_info */
|
/* Copy jited_line_info */
|
||||||
prog_linfo->nr_jited_func = nr_jited_func;
|
prog_linfo->nr_jited_func = nr_jited_func;
|
||||||
prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
|
prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
|
||||||
prog_linfo->raw_jited_linfo = malloc(nr_linfo *
|
data_sz = (__u64)nr_linfo * prog_linfo->jited_rec_size;
|
||||||
prog_linfo->jited_rec_size);
|
prog_linfo->raw_jited_linfo = malloc(data_sz);
|
||||||
if (!prog_linfo->raw_jited_linfo)
|
if (!prog_linfo->raw_jited_linfo)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
memcpy(prog_linfo->raw_jited_linfo,
|
memcpy(prog_linfo->raw_jited_linfo,
|
||||||
(void *)(long)info->jited_line_info,
|
(void *)(long)info->jited_line_info, data_sz);
|
||||||
nr_linfo * prog_linfo->jited_rec_size);
|
|
||||||
|
|
||||||
/* Number of jited_line_info per jited func */
|
/* Number of jited_line_info per jited func */
|
||||||
prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
|
prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
|
||||||
|
|||||||
195
src/bpf_tracing.h
Normal file
195
src/bpf_tracing.h
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
#ifndef __BPF_TRACING_H__
|
||||||
|
#define __BPF_TRACING_H__
|
||||||
|
|
||||||
|
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
||||||
|
#if defined(__TARGET_ARCH_x86)
|
||||||
|
#define bpf_target_x86
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_s390)
|
||||||
|
#define bpf_target_s390
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_arm)
|
||||||
|
#define bpf_target_arm
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_arm64)
|
||||||
|
#define bpf_target_arm64
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_mips)
|
||||||
|
#define bpf_target_mips
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_powerpc)
|
||||||
|
#define bpf_target_powerpc
|
||||||
|
#define bpf_target_defined
|
||||||
|
#elif defined(__TARGET_ARCH_sparc)
|
||||||
|
#define bpf_target_sparc
|
||||||
|
#define bpf_target_defined
|
||||||
|
#else
|
||||||
|
#undef bpf_target_defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Fall back to what the compiler says */
|
||||||
|
#ifndef bpf_target_defined
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
#define bpf_target_x86
|
||||||
|
#elif defined(__s390__)
|
||||||
|
#define bpf_target_s390
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define bpf_target_arm
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define bpf_target_arm64
|
||||||
|
#elif defined(__mips__)
|
||||||
|
#define bpf_target_mips
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
#define bpf_target_powerpc
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
#define bpf_target_sparc
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(bpf_target_x86)
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->di)
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->si)
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->dx)
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->cx)
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->r8)
|
||||||
|
#define PT_REGS_RET(x) ((x)->sp)
|
||||||
|
#define PT_REGS_FP(x) ((x)->bp)
|
||||||
|
#define PT_REGS_RC(x) ((x)->ax)
|
||||||
|
#define PT_REGS_SP(x) ((x)->sp)
|
||||||
|
#define PT_REGS_IP(x) ((x)->ip)
|
||||||
|
#else
|
||||||
|
#ifdef __i386__
|
||||||
|
/* i386 kernel is built with -mregparm=3 */
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->eax)
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->edx)
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->ecx)
|
||||||
|
#define PT_REGS_PARM4(x) 0
|
||||||
|
#define PT_REGS_PARM5(x) 0
|
||||||
|
#define PT_REGS_RET(x) ((x)->esp)
|
||||||
|
#define PT_REGS_FP(x) ((x)->ebp)
|
||||||
|
#define PT_REGS_RC(x) ((x)->eax)
|
||||||
|
#define PT_REGS_SP(x) ((x)->esp)
|
||||||
|
#define PT_REGS_IP(x) ((x)->eip)
|
||||||
|
#else
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->rdi)
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->rsi)
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->rdx)
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->rcx)
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->r8)
|
||||||
|
#define PT_REGS_RET(x) ((x)->rsp)
|
||||||
|
#define PT_REGS_FP(x) ((x)->rbp)
|
||||||
|
#define PT_REGS_RC(x) ((x)->rax)
|
||||||
|
#define PT_REGS_SP(x) ((x)->rsp)
|
||||||
|
#define PT_REGS_IP(x) ((x)->rip)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(bpf_target_s390)
|
||||||
|
|
||||||
|
/* s390 provides user_pt_regs instead of struct pt_regs to userspace */
|
||||||
|
struct pt_regs;
|
||||||
|
#define PT_REGS_S390 const volatile user_pt_regs
|
||||||
|
#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2])
|
||||||
|
#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3])
|
||||||
|
#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4])
|
||||||
|
#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5])
|
||||||
|
#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6])
|
||||||
|
#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14])
|
||||||
|
/* Works only with CONFIG_FRAME_POINTER */
|
||||||
|
#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11])
|
||||||
|
#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2])
|
||||||
|
#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15])
|
||||||
|
#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr)
|
||||||
|
|
||||||
|
#elif defined(bpf_target_arm)
|
||||||
|
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->uregs[0])
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->uregs[1])
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->uregs[2])
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->uregs[3])
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->uregs[4])
|
||||||
|
#define PT_REGS_RET(x) ((x)->uregs[14])
|
||||||
|
#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */
|
||||||
|
#define PT_REGS_RC(x) ((x)->uregs[0])
|
||||||
|
#define PT_REGS_SP(x) ((x)->uregs[13])
|
||||||
|
#define PT_REGS_IP(x) ((x)->uregs[12])
|
||||||
|
|
||||||
|
#elif defined(bpf_target_arm64)
|
||||||
|
|
||||||
|
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||||
|
struct pt_regs;
|
||||||
|
#define PT_REGS_ARM64 const volatile struct user_pt_regs
|
||||||
|
#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])
|
||||||
|
#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])
|
||||||
|
#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2])
|
||||||
|
#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3])
|
||||||
|
#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4])
|
||||||
|
#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30])
|
||||||
|
/* Works only with CONFIG_FRAME_POINTER */
|
||||||
|
#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29])
|
||||||
|
#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0])
|
||||||
|
#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)
|
||||||
|
#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc)
|
||||||
|
|
||||||
|
#elif defined(bpf_target_mips)
|
||||||
|
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->regs[4])
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->regs[5])
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->regs[6])
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->regs[7])
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->regs[8])
|
||||||
|
#define PT_REGS_RET(x) ((x)->regs[31])
|
||||||
|
#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */
|
||||||
|
#define PT_REGS_RC(x) ((x)->regs[1])
|
||||||
|
#define PT_REGS_SP(x) ((x)->regs[29])
|
||||||
|
#define PT_REGS_IP(x) ((x)->cp0_epc)
|
||||||
|
|
||||||
|
#elif defined(bpf_target_powerpc)
|
||||||
|
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->gpr[3])
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->gpr[4])
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->gpr[5])
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->gpr[6])
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->gpr[7])
|
||||||
|
#define PT_REGS_RC(x) ((x)->gpr[3])
|
||||||
|
#define PT_REGS_SP(x) ((x)->sp)
|
||||||
|
#define PT_REGS_IP(x) ((x)->nip)
|
||||||
|
|
||||||
|
#elif defined(bpf_target_sparc)
|
||||||
|
|
||||||
|
#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])
|
||||||
|
#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1])
|
||||||
|
#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2])
|
||||||
|
#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3])
|
||||||
|
#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4])
|
||||||
|
#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7])
|
||||||
|
#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])
|
||||||
|
#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])
|
||||||
|
|
||||||
|
/* Should this also be a bpf_target check for the sparc case? */
|
||||||
|
#if defined(__arch64__)
|
||||||
|
#define PT_REGS_IP(x) ((x)->tpc)
|
||||||
|
#else
|
||||||
|
#define PT_REGS_IP(x) ((x)->pc)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(bpf_target_powerpc)
|
||||||
|
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; })
|
||||||
|
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||||||
|
#elif defined(bpf_target_sparc)
|
||||||
|
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); })
|
||||||
|
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||||||
|
#else
|
||||||
|
#define BPF_KPROBE_READ_RET_IP(ip, ctx) \
|
||||||
|
({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
||||||
|
#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \
|
||||||
|
({ bpf_probe_read(&(ip), sizeof(ip), \
|
||||||
|
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
485
src/btf.c
485
src/btf.c
@@ -1,12 +1,17 @@
|
|||||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
/* Copyright (c) 2018 Facebook */
|
/* Copyright (c) 2018 Facebook */
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
#include <gelf.h>
|
#include <gelf.h>
|
||||||
@@ -16,15 +21,11 @@
|
|||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
|
||||||
#define BTF_MAX_NR_TYPES 0x7fffffff
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
#define BTF_MAX_STR_OFFSET 0x7fffffff
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
#define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \
|
#define BTF_MAX_NR_TYPES 0x7fffffffU
|
||||||
((k) == BTF_KIND_VOLATILE) || \
|
#define BTF_MAX_STR_OFFSET 0x7fffffffU
|
||||||
((k) == BTF_KIND_CONST) || \
|
|
||||||
((k) == BTF_KIND_RESTRICT))
|
|
||||||
|
|
||||||
#define IS_VAR(k) ((k) == BTF_KIND_VAR)
|
|
||||||
|
|
||||||
static struct btf_type btf_void;
|
static struct btf_type btf_void;
|
||||||
|
|
||||||
@@ -42,47 +43,6 @@ struct btf {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btf_ext_info {
|
|
||||||
/*
|
|
||||||
* info points to the individual info section (e.g. func_info and
|
|
||||||
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
|
||||||
*/
|
|
||||||
void *info;
|
|
||||||
__u32 rec_size;
|
|
||||||
__u32 len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct btf_ext {
|
|
||||||
union {
|
|
||||||
struct btf_ext_header *hdr;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
struct btf_ext_info func_info;
|
|
||||||
struct btf_ext_info line_info;
|
|
||||||
__u32 data_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct btf_ext_info_sec {
|
|
||||||
__u32 sec_name_off;
|
|
||||||
__u32 num_info;
|
|
||||||
/* Followed by num_info * record_size number of bytes */
|
|
||||||
__u8 data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The minimum bpf_func_info checked by the loader */
|
|
||||||
struct bpf_func_info_min {
|
|
||||||
__u32 insn_off;
|
|
||||||
__u32 type_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The minimum bpf_line_info checked by the loader */
|
|
||||||
struct bpf_line_info_min {
|
|
||||||
__u32 insn_off;
|
|
||||||
__u32 file_name_off;
|
|
||||||
__u32 line_off;
|
|
||||||
__u32 line_col;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline __u64 ptr_to_u64(const void *ptr)
|
static inline __u64 ptr_to_u64(const void *ptr)
|
||||||
{
|
{
|
||||||
return (__u64) (unsigned long) ptr;
|
return (__u64) (unsigned long) ptr;
|
||||||
@@ -97,7 +57,7 @@ static int btf_add_type(struct btf *btf, struct btf_type *t)
|
|||||||
if (btf->types_size == BTF_MAX_NR_TYPES)
|
if (btf->types_size == BTF_MAX_NR_TYPES)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
expand_by = max(btf->types_size >> 2, 16);
|
expand_by = max(btf->types_size >> 2, 16U);
|
||||||
new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by);
|
new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by);
|
||||||
|
|
||||||
new_types = realloc(btf->types, sizeof(*new_types) * new_size);
|
new_types = realloc(btf->types, sizeof(*new_types) * new_size);
|
||||||
@@ -192,9 +152,9 @@ static int btf_parse_str_sec(struct btf *btf)
|
|||||||
static int btf_type_size(struct btf_type *t)
|
static int btf_type_size(struct btf_type *t)
|
||||||
{
|
{
|
||||||
int base_size = sizeof(struct btf_type);
|
int base_size = sizeof(struct btf_type);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
case BTF_KIND_CONST:
|
case BTF_KIND_CONST:
|
||||||
case BTF_KIND_VOLATILE:
|
case BTF_KIND_VOLATILE:
|
||||||
@@ -219,7 +179,7 @@ static int btf_type_size(struct btf_type *t)
|
|||||||
case BTF_KIND_DATASEC:
|
case BTF_KIND_DATASEC:
|
||||||
return base_size + vlen * sizeof(struct btf_var_secinfo);
|
return base_size + vlen * sizeof(struct btf_var_secinfo);
|
||||||
default:
|
default:
|
||||||
pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info));
|
pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +223,7 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
|
|||||||
|
|
||||||
static bool btf_type_is_void(const struct btf_type *t)
|
static bool btf_type_is_void(const struct btf_type *t)
|
||||||
{
|
{
|
||||||
return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
|
return t == &btf_void || btf_is_fwd(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_type_is_void_or_null(const struct btf_type *t)
|
static bool btf_type_is_void_or_null(const struct btf_type *t)
|
||||||
@@ -284,7 +244,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
|||||||
t = btf__type_by_id(btf, type_id);
|
t = btf__type_by_id(btf, type_id);
|
||||||
for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
|
for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
|
||||||
i++) {
|
i++) {
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
case BTF_KIND_STRUCT:
|
case BTF_KIND_STRUCT:
|
||||||
case BTF_KIND_UNION:
|
case BTF_KIND_UNION:
|
||||||
@@ -303,7 +263,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
|||||||
type_id = t->type;
|
type_id = t->type;
|
||||||
break;
|
break;
|
||||||
case BTF_KIND_ARRAY:
|
case BTF_KIND_ARRAY:
|
||||||
array = (const struct btf_array *)(t + 1);
|
array = btf_array(t);
|
||||||
if (nelems && array->nelems > UINT32_MAX / nelems)
|
if (nelems && array->nelems > UINT32_MAX / nelems)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
nelems *= array->nelems;
|
nelems *= array->nelems;
|
||||||
@@ -316,16 +276,54 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
|||||||
t = btf__type_by_id(btf, type_id);
|
t = btf__type_by_id(btf, type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
done:
|
|
||||||
if (nelems && size > UINT32_MAX / nelems)
|
if (nelems && size > UINT32_MAX / nelems)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
return nelems * size;
|
return nelems * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btf__align_of(const struct btf *btf, __u32 id)
|
||||||
|
{
|
||||||
|
const struct btf_type *t = btf__type_by_id(btf, id);
|
||||||
|
__u16 kind = btf_kind(t);
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case BTF_KIND_INT:
|
||||||
|
case BTF_KIND_ENUM:
|
||||||
|
return min(sizeof(void *), (size_t)t->size);
|
||||||
|
case BTF_KIND_PTR:
|
||||||
|
return sizeof(void *);
|
||||||
|
case BTF_KIND_TYPEDEF:
|
||||||
|
case BTF_KIND_VOLATILE:
|
||||||
|
case BTF_KIND_CONST:
|
||||||
|
case BTF_KIND_RESTRICT:
|
||||||
|
return btf__align_of(btf, t->type);
|
||||||
|
case BTF_KIND_ARRAY:
|
||||||
|
return btf__align_of(btf, btf_array(t)->type);
|
||||||
|
case BTF_KIND_STRUCT:
|
||||||
|
case BTF_KIND_UNION: {
|
||||||
|
const struct btf_member *m = btf_members(t);
|
||||||
|
__u16 vlen = btf_vlen(t);
|
||||||
|
int i, max_align = 1, align;
|
||||||
|
|
||||||
|
for (i = 0; i < vlen; i++, m++) {
|
||||||
|
align = btf__align_of(btf, m->type);
|
||||||
|
if (align <= 0)
|
||||||
|
return align;
|
||||||
|
max_align = max(max_align, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_align;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pr_warn("unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int btf__resolve_type(const struct btf *btf, __u32 type_id)
|
int btf__resolve_type(const struct btf *btf, __u32 type_id)
|
||||||
{
|
{
|
||||||
const struct btf_type *t;
|
const struct btf_type *t;
|
||||||
@@ -334,8 +332,7 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
|
|||||||
t = btf__type_by_id(btf, type_id);
|
t = btf__type_by_id(btf, type_id);
|
||||||
while (depth < MAX_RESOLVE_DEPTH &&
|
while (depth < MAX_RESOLVE_DEPTH &&
|
||||||
!btf_type_is_void_or_null(t) &&
|
!btf_type_is_void_or_null(t) &&
|
||||||
(IS_MODIFIER(BTF_INFO_KIND(t->info)) ||
|
(btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
|
||||||
IS_VAR(BTF_INFO_KIND(t->info)))) {
|
|
||||||
type_id = t->type;
|
type_id = t->type;
|
||||||
t = btf__type_by_id(btf, type_id);
|
t = btf__type_by_id(btf, type_id);
|
||||||
depth++;
|
depth++;
|
||||||
@@ -365,6 +362,28 @@ __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
|
||||||
|
__u32 kind)
|
||||||
|
{
|
||||||
|
__u32 i;
|
||||||
|
|
||||||
|
if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 1; i <= btf->nr_types; i++) {
|
||||||
|
const struct btf_type *t = btf->types[i];
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (btf_kind(t) != kind)
|
||||||
|
continue;
|
||||||
|
name = btf__name_by_offset(btf, t->name_off);
|
||||||
|
if (name && !strcmp(type_name, name))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
void btf__free(struct btf *btf)
|
void btf__free(struct btf *btf)
|
||||||
{
|
{
|
||||||
if (!btf)
|
if (!btf)
|
||||||
@@ -419,9 +438,9 @@ done:
|
|||||||
|
|
||||||
static bool btf_check_endianness(const GElf_Ehdr *ehdr)
|
static bool btf_check_endianness(const GElf_Ehdr *ehdr)
|
||||||
{
|
{
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
return ehdr->e_ident[EI_DATA] == ELFDATA2LSB;
|
return ehdr->e_ident[EI_DATA] == ELFDATA2LSB;
|
||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
return ehdr->e_ident[EI_DATA] == ELFDATA2MSB;
|
return ehdr->e_ident[EI_DATA] == ELFDATA2MSB;
|
||||||
#else
|
#else
|
||||||
# error "Unrecognized __BYTE_ORDER__"
|
# error "Unrecognized __BYTE_ORDER__"
|
||||||
@@ -438,14 +457,14 @@ struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
|
|||||||
GElf_Ehdr ehdr;
|
GElf_Ehdr ehdr;
|
||||||
|
|
||||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||||
pr_warning("failed to init libelf for %s\n", path);
|
pr_warn("failed to init libelf for %s\n", path);
|
||||||
return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
|
return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warning("failed to open %s: %s\n", path, strerror(errno));
|
pr_warn("failed to open %s: %s\n", path, strerror(errno));
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,19 +472,19 @@ struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
|
|||||||
|
|
||||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||||
if (!elf) {
|
if (!elf) {
|
||||||
pr_warning("failed to open %s as ELF file\n", path);
|
pr_warn("failed to open %s as ELF file\n", path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!gelf_getehdr(elf, &ehdr)) {
|
if (!gelf_getehdr(elf, &ehdr)) {
|
||||||
pr_warning("failed to get EHDR from %s\n", path);
|
pr_warn("failed to get EHDR from %s\n", path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!btf_check_endianness(&ehdr)) {
|
if (!btf_check_endianness(&ehdr)) {
|
||||||
pr_warning("non-native ELF endianness is not supported\n");
|
pr_warn("non-native ELF endianness is not supported\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!elf_rawdata(elf_getscn(elf, ehdr.e_shstrndx), NULL)) {
|
if (!elf_rawdata(elf_getscn(elf, ehdr.e_shstrndx), NULL)) {
|
||||||
pr_warning("failed to get e_shstrndx from %s\n", path);
|
pr_warn("failed to get e_shstrndx from %s\n", path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,29 +494,29 @@ struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
|
|||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
if (gelf_getshdr(scn, &sh) != &sh) {
|
if (gelf_getshdr(scn, &sh) != &sh) {
|
||||||
pr_warning("failed to get section(%d) header from %s\n",
|
pr_warn("failed to get section(%d) header from %s\n",
|
||||||
idx, path);
|
idx, path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
|
name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
pr_warning("failed to get section(%d) name from %s\n",
|
pr_warn("failed to get section(%d) name from %s\n",
|
||||||
idx, path);
|
idx, path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strcmp(name, BTF_ELF_SEC) == 0) {
|
if (strcmp(name, BTF_ELF_SEC) == 0) {
|
||||||
btf_data = elf_getdata(scn, 0);
|
btf_data = elf_getdata(scn, 0);
|
||||||
if (!btf_data) {
|
if (!btf_data) {
|
||||||
pr_warning("failed to get section(%d, %s) data from %s\n",
|
pr_warn("failed to get section(%d, %s) data from %s\n",
|
||||||
idx, name, path);
|
idx, name, path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
} else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
||||||
btf_ext_data = elf_getdata(scn, 0);
|
btf_ext_data = elf_getdata(scn, 0);
|
||||||
if (!btf_ext_data) {
|
if (!btf_ext_data) {
|
||||||
pr_warning("failed to get section(%d, %s) data from %s\n",
|
pr_warn("failed to get section(%d, %s) data from %s\n",
|
||||||
idx, name, path);
|
idx, name, path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -554,11 +573,11 @@ static int compare_vsi_off(const void *_a, const void *_b)
|
|||||||
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
||||||
struct btf_type *t)
|
struct btf_type *t)
|
||||||
{
|
{
|
||||||
__u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info);
|
__u32 size = 0, off = 0, i, vars = btf_vlen(t);
|
||||||
const char *name = btf__name_by_offset(btf, t->name_off);
|
const char *name = btf__name_by_offset(btf, t->name_off);
|
||||||
const struct btf_type *t_var;
|
const struct btf_type *t_var;
|
||||||
struct btf_var_secinfo *vsi;
|
struct btf_var_secinfo *vsi;
|
||||||
struct btf_var *var;
|
const struct btf_var *var;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@@ -566,6 +585,12 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .extern datasec size and var offsets were set correctly during
|
||||||
|
* extern collection step, so just skip straight to sorting variables
|
||||||
|
*/
|
||||||
|
if (t->size)
|
||||||
|
goto sort_vars;
|
||||||
|
|
||||||
ret = bpf_object__section_size(obj, name, &size);
|
ret = bpf_object__section_size(obj, name, &size);
|
||||||
if (ret || !size || (t->size && t->size != size)) {
|
if (ret || !size || (t->size && t->size != size)) {
|
||||||
pr_debug("Invalid size for section %s: %u bytes\n", name, size);
|
pr_debug("Invalid size for section %s: %u bytes\n", name, size);
|
||||||
@@ -574,12 +599,11 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
|||||||
|
|
||||||
t->size = size;
|
t->size = size;
|
||||||
|
|
||||||
for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1);
|
for (i = 0, vsi = btf_var_secinfos(t); i < vars; i++, vsi++) {
|
||||||
i < vars; i++, vsi++) {
|
|
||||||
t_var = btf__type_by_id(btf, vsi->type);
|
t_var = btf__type_by_id(btf, vsi->type);
|
||||||
var = (struct btf_var *)(t_var + 1);
|
var = btf_var(t_var);
|
||||||
|
|
||||||
if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) {
|
if (!btf_is_var(t_var)) {
|
||||||
pr_debug("Non-VAR type seen in section %s\n", name);
|
pr_debug("Non-VAR type seen in section %s\n", name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -595,14 +619,16 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
|||||||
|
|
||||||
ret = bpf_object__variable_offset(obj, name, &off);
|
ret = bpf_object__variable_offset(obj, name, &off);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_debug("No offset found in symbol table for VAR %s\n", name);
|
pr_debug("No offset found in symbol table for VAR %s\n",
|
||||||
|
name);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
vsi->offset = off;
|
vsi->offset = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(t + 1, vars, sizeof(*vsi), compare_vsi_off);
|
sort_vars:
|
||||||
|
qsort(btf_var_secinfos(t), vars, sizeof(*vsi), compare_vsi_off);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +645,7 @@ int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
|
|||||||
* is section size and global variable offset. We use
|
* is section size and global variable offset. We use
|
||||||
* the info from the ELF itself for this purpose.
|
* the info from the ELF itself for this purpose.
|
||||||
*/
|
*/
|
||||||
if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) {
|
if (btf_is_datasec(t)) {
|
||||||
err = btf_fixup_datasec(obj, btf, t);
|
err = btf_fixup_datasec(obj, btf, t);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
@@ -648,9 +674,9 @@ int btf__load(struct btf *btf)
|
|||||||
log_buf, log_buf_size, false);
|
log_buf, log_buf_size, false);
|
||||||
if (btf->fd < 0) {
|
if (btf->fd < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warning("Error loading BTF: %s(%d)\n", strerror(errno), errno);
|
pr_warn("Error loading BTF: %s(%d)\n", strerror(errno), errno);
|
||||||
if (*log_buf)
|
if (*log_buf)
|
||||||
pr_warning("%s\n", log_buf);
|
pr_warn("%s\n", log_buf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,8 +781,8 @@ int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
|||||||
|
|
||||||
if (snprintf(container_name, max_name, "____btf_map_%s", map_name) ==
|
if (snprintf(container_name, max_name, "____btf_map_%s", map_name) ==
|
||||||
max_name) {
|
max_name) {
|
||||||
pr_warning("map:%s length of '____btf_map_%s' is too long\n",
|
pr_warn("map:%s length of '____btf_map_%s' is too long\n",
|
||||||
map_name, map_name);
|
map_name, map_name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,42 +795,41 @@ int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
|||||||
|
|
||||||
container_type = btf__type_by_id(btf, container_id);
|
container_type = btf__type_by_id(btf, container_id);
|
||||||
if (!container_type) {
|
if (!container_type) {
|
||||||
pr_warning("map:%s cannot find BTF type for container_id:%u\n",
|
pr_warn("map:%s cannot find BTF type for container_id:%u\n",
|
||||||
map_name, container_id);
|
map_name, container_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BTF_INFO_KIND(container_type->info) != BTF_KIND_STRUCT ||
|
if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) {
|
||||||
BTF_INFO_VLEN(container_type->info) < 2) {
|
pr_warn("map:%s container_name:%s is an invalid container struct\n",
|
||||||
pr_warning("map:%s container_name:%s is an invalid container struct\n",
|
map_name, container_name);
|
||||||
map_name, container_name);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = (struct btf_member *)(container_type + 1);
|
key = btf_members(container_type);
|
||||||
value = key + 1;
|
value = key + 1;
|
||||||
|
|
||||||
key_size = btf__resolve_size(btf, key->type);
|
key_size = btf__resolve_size(btf, key->type);
|
||||||
if (key_size < 0) {
|
if (key_size < 0) {
|
||||||
pr_warning("map:%s invalid BTF key_type_size\n", map_name);
|
pr_warn("map:%s invalid BTF key_type_size\n", map_name);
|
||||||
return key_size;
|
return key_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expected_key_size != key_size) {
|
if (expected_key_size != key_size) {
|
||||||
pr_warning("map:%s btf_key_type_size:%u != map_def_key_size:%u\n",
|
pr_warn("map:%s btf_key_type_size:%u != map_def_key_size:%u\n",
|
||||||
map_name, (__u32)key_size, expected_key_size);
|
map_name, (__u32)key_size, expected_key_size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_size = btf__resolve_size(btf, value->type);
|
value_size = btf__resolve_size(btf, value->type);
|
||||||
if (value_size < 0) {
|
if (value_size < 0) {
|
||||||
pr_warning("map:%s invalid BTF value_type_size\n", map_name);
|
pr_warn("map:%s invalid BTF value_type_size\n", map_name);
|
||||||
return value_size;
|
return value_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expected_value_size != value_size) {
|
if (expected_value_size != value_size) {
|
||||||
pr_warning("map:%s btf_value_type_size:%u != map_def_value_size:%u\n",
|
pr_warn("map:%s btf_value_type_size:%u != map_def_value_size:%u\n",
|
||||||
map_name, (__u32)value_size, expected_value_size);
|
map_name, (__u32)value_size, expected_value_size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -831,6 +856,9 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
|
|||||||
/* The start of the info sec (including the __u32 record_size). */
|
/* The start of the info sec (including the __u32 record_size). */
|
||||||
void *info;
|
void *info;
|
||||||
|
|
||||||
|
if (ext_sec->len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (ext_sec->off & 0x03) {
|
if (ext_sec->off & 0x03) {
|
||||||
pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
|
pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
|
||||||
ext_sec->desc);
|
ext_sec->desc);
|
||||||
@@ -934,11 +962,24 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
|
|||||||
return btf_ext_setup_info(btf_ext, ¶m);
|
return btf_ext_setup_info(btf_ext, ¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btf_ext_setup_field_reloc(struct btf_ext *btf_ext)
|
||||||
|
{
|
||||||
|
struct btf_ext_sec_setup_param param = {
|
||||||
|
.off = btf_ext->hdr->field_reloc_off,
|
||||||
|
.len = btf_ext->hdr->field_reloc_len,
|
||||||
|
.min_rec_size = sizeof(struct bpf_field_reloc),
|
||||||
|
.ext_info = &btf_ext->field_reloc_info,
|
||||||
|
.desc = "field_reloc",
|
||||||
|
};
|
||||||
|
|
||||||
|
return btf_ext_setup_info(btf_ext, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
|
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
|
||||||
{
|
{
|
||||||
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||||
|
|
||||||
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
|
if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
|
||||||
data_size < hdr->hdr_len) {
|
data_size < hdr->hdr_len) {
|
||||||
pr_debug("BTF.ext header not found");
|
pr_debug("BTF.ext header not found");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -996,6 +1037,9 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
|||||||
}
|
}
|
||||||
memcpy(btf_ext->data, data, size);
|
memcpy(btf_ext->data, data, size);
|
||||||
|
|
||||||
|
if (btf_ext->hdr->hdr_len <
|
||||||
|
offsetofend(struct btf_ext_header, line_info_len))
|
||||||
|
goto done;
|
||||||
err = btf_ext_setup_func_info(btf_ext);
|
err = btf_ext_setup_func_info(btf_ext);
|
||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1004,6 +1048,13 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
|||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (btf_ext->hdr->hdr_len <
|
||||||
|
offsetofend(struct btf_ext_header, field_reloc_len))
|
||||||
|
goto done;
|
||||||
|
err = btf_ext_setup_field_reloc(btf_ext);
|
||||||
|
if (err)
|
||||||
|
goto done;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (err) {
|
if (err) {
|
||||||
btf_ext__free(btf_ext);
|
btf_ext__free(btf_ext);
|
||||||
@@ -1354,7 +1405,7 @@ static int btf_dedup_hypot_map_add(struct btf_dedup *d,
|
|||||||
if (d->hypot_cnt == d->hypot_cap) {
|
if (d->hypot_cnt == d->hypot_cap) {
|
||||||
__u32 *new_list;
|
__u32 *new_list;
|
||||||
|
|
||||||
d->hypot_cap += max(16, d->hypot_cap / 2);
|
d->hypot_cap += max((size_t)16, d->hypot_cap / 2);
|
||||||
new_list = realloc(d->hypot_list, sizeof(__u32) * d->hypot_cap);
|
new_list = realloc(d->hypot_list, sizeof(__u32) * d->hypot_cap);
|
||||||
if (!new_list)
|
if (!new_list)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -1440,10 +1491,9 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
|||||||
d->map[0] = 0;
|
d->map[0] = 0;
|
||||||
for (i = 1; i <= btf->nr_types; i++) {
|
for (i = 1; i <= btf->nr_types; i++) {
|
||||||
struct btf_type *t = d->btf->types[i];
|
struct btf_type *t = d->btf->types[i];
|
||||||
__u16 kind = BTF_INFO_KIND(t->info);
|
|
||||||
|
|
||||||
/* VAR and DATASEC are never deduped and are self-canonical */
|
/* VAR and DATASEC are never deduped and are self-canonical */
|
||||||
if (kind == BTF_KIND_VAR || kind == BTF_KIND_DATASEC)
|
if (btf_is_var(t) || btf_is_datasec(t))
|
||||||
d->map[i] = i;
|
d->map[i] = i;
|
||||||
else
|
else
|
||||||
d->map[i] = BTF_UNPROCESSED_ID;
|
d->map[i] = BTF_UNPROCESSED_ID;
|
||||||
@@ -1484,11 +1534,11 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_STRUCT:
|
case BTF_KIND_STRUCT:
|
||||||
case BTF_KIND_UNION: {
|
case BTF_KIND_UNION: {
|
||||||
struct btf_member *m = (struct btf_member *)(t + 1);
|
struct btf_member *m = btf_members(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
for (j = 0; j < vlen; j++) {
|
for (j = 0; j < vlen; j++) {
|
||||||
r = fn(&m->name_off, ctx);
|
r = fn(&m->name_off, ctx);
|
||||||
@@ -1499,8 +1549,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BTF_KIND_ENUM: {
|
case BTF_KIND_ENUM: {
|
||||||
struct btf_enum *m = (struct btf_enum *)(t + 1);
|
struct btf_enum *m = btf_enum(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
for (j = 0; j < vlen; j++) {
|
for (j = 0; j < vlen; j++) {
|
||||||
r = fn(&m->name_off, ctx);
|
r = fn(&m->name_off, ctx);
|
||||||
@@ -1511,8 +1561,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
struct btf_param *m = (struct btf_param *)(t + 1);
|
struct btf_param *m = btf_params(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
for (j = 0; j < vlen; j++) {
|
for (j = 0; j < vlen; j++) {
|
||||||
r = fn(&m->name_off, ctx);
|
r = fn(&m->name_off, ctx);
|
||||||
@@ -1651,7 +1701,7 @@ static int btf_dedup_strings(struct btf_dedup *d)
|
|||||||
if (strs.cnt + 1 > strs.cap) {
|
if (strs.cnt + 1 > strs.cap) {
|
||||||
struct btf_str_ptr *new_ptrs;
|
struct btf_str_ptr *new_ptrs;
|
||||||
|
|
||||||
strs.cap += max(strs.cnt / 2, 16);
|
strs.cap += max(strs.cnt / 2, 16U);
|
||||||
new_ptrs = realloc(strs.ptrs,
|
new_ptrs = realloc(strs.ptrs,
|
||||||
sizeof(strs.ptrs[0]) * strs.cap);
|
sizeof(strs.ptrs[0]) * strs.cap);
|
||||||
if (!new_ptrs) {
|
if (!new_ptrs) {
|
||||||
@@ -1801,16 +1851,16 @@ static long btf_hash_enum(struct btf_type *t)
|
|||||||
/* Check structural equality of two ENUMs. */
|
/* Check structural equality of two ENUMs. */
|
||||||
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
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))
|
if (!btf_equal_common(t1, t2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vlen = BTF_INFO_VLEN(t1->info);
|
vlen = btf_vlen(t1);
|
||||||
m1 = (struct btf_enum *)(t1 + 1);
|
m1 = btf_enum(t1);
|
||||||
m2 = (struct btf_enum *)(t2 + 1);
|
m2 = btf_enum(t2);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
if (m1->name_off != m2->name_off || m1->val != m2->val)
|
if (m1->name_off != m2->name_off || m1->val != m2->val)
|
||||||
return false;
|
return false;
|
||||||
@@ -1822,8 +1872,7 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *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_INFO_KIND(t->info) == BTF_KIND_ENUM &&
|
return btf_is_enum(t) && btf_vlen(t) == 0;
|
||||||
BTF_INFO_VLEN(t->info) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
||||||
@@ -1843,8 +1892,8 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
|||||||
*/
|
*/
|
||||||
static long btf_hash_struct(struct btf_type *t)
|
static long btf_hash_struct(struct btf_type *t)
|
||||||
{
|
{
|
||||||
struct btf_member *member = (struct btf_member *)(t + 1);
|
const struct btf_member *member = btf_members(t);
|
||||||
__u32 vlen = BTF_INFO_VLEN(t->info);
|
__u32 vlen = btf_vlen(t);
|
||||||
long h = btf_hash_common(t);
|
long h = btf_hash_common(t);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1864,16 +1913,16 @@ static long btf_hash_struct(struct btf_type *t)
|
|||||||
*/
|
*/
|
||||||
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
struct btf_member *m1, *m2;
|
const struct btf_member *m1, *m2;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
if (!btf_equal_common(t1, t2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vlen = BTF_INFO_VLEN(t1->info);
|
vlen = btf_vlen(t1);
|
||||||
m1 = (struct btf_member *)(t1 + 1);
|
m1 = btf_members(t1);
|
||||||
m2 = (struct btf_member *)(t2 + 1);
|
m2 = btf_members(t2);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
if (m1->name_off != m2->name_off || m1->offset != m2->offset)
|
if (m1->name_off != m2->name_off || m1->offset != m2->offset)
|
||||||
return false;
|
return false;
|
||||||
@@ -1890,7 +1939,7 @@ static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
|||||||
*/
|
*/
|
||||||
static long btf_hash_array(struct btf_type *t)
|
static long btf_hash_array(struct btf_type *t)
|
||||||
{
|
{
|
||||||
struct btf_array *info = (struct btf_array *)(t + 1);
|
const struct btf_array *info = btf_array(t);
|
||||||
long h = btf_hash_common(t);
|
long h = btf_hash_common(t);
|
||||||
|
|
||||||
h = hash_combine(h, info->type);
|
h = hash_combine(h, info->type);
|
||||||
@@ -1908,13 +1957,13 @@ static long btf_hash_array(struct btf_type *t)
|
|||||||
*/
|
*/
|
||||||
static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
struct btf_array *info1, *info2;
|
const struct btf_array *info1, *info2;
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
if (!btf_equal_common(t1, t2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
info1 = (struct btf_array *)(t1 + 1);
|
info1 = btf_array(t1);
|
||||||
info2 = (struct btf_array *)(t2 + 1);
|
info2 = btf_array(t2);
|
||||||
return info1->type == info2->type &&
|
return info1->type == info2->type &&
|
||||||
info1->index_type == info2->index_type &&
|
info1->index_type == info2->index_type &&
|
||||||
info1->nelems == info2->nelems;
|
info1->nelems == info2->nelems;
|
||||||
@@ -1927,14 +1976,10 @@ static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
|
|||||||
*/
|
*/
|
||||||
static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
struct btf_array *info1, *info2;
|
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
if (!btf_equal_common(t1, t2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
info1 = (struct btf_array *)(t1 + 1);
|
return btf_array(t1)->nelems == btf_array(t2)->nelems;
|
||||||
info2 = (struct btf_array *)(t2 + 1);
|
|
||||||
return info1->nelems == info2->nelems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1944,8 +1989,8 @@ static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
|
|||||||
*/
|
*/
|
||||||
static long btf_hash_fnproto(struct btf_type *t)
|
static long btf_hash_fnproto(struct btf_type *t)
|
||||||
{
|
{
|
||||||
struct btf_param *member = (struct btf_param *)(t + 1);
|
const struct btf_param *member = btf_params(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
long h = btf_hash_common(t);
|
long h = btf_hash_common(t);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1966,16 +2011,16 @@ static long btf_hash_fnproto(struct btf_type *t)
|
|||||||
*/
|
*/
|
||||||
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
struct btf_param *m1, *m2;
|
const struct btf_param *m1, *m2;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!btf_equal_common(t1, t2))
|
if (!btf_equal_common(t1, t2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vlen = BTF_INFO_VLEN(t1->info);
|
vlen = btf_vlen(t1);
|
||||||
m1 = (struct btf_param *)(t1 + 1);
|
m1 = btf_params(t1);
|
||||||
m2 = (struct btf_param *)(t2 + 1);
|
m2 = btf_params(t2);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
if (m1->name_off != m2->name_off || m1->type != m2->type)
|
if (m1->name_off != m2->name_off || m1->type != m2->type)
|
||||||
return false;
|
return false;
|
||||||
@@ -1992,7 +2037,7 @@ static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
|
|||||||
*/
|
*/
|
||||||
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
|
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||||
{
|
{
|
||||||
struct btf_param *m1, *m2;
|
const struct btf_param *m1, *m2;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -2000,9 +2045,9 @@ static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
|
|||||||
if (t1->name_off != t2->name_off || t1->info != t2->info)
|
if (t1->name_off != t2->name_off || t1->info != t2->info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vlen = BTF_INFO_VLEN(t1->info);
|
vlen = btf_vlen(t1);
|
||||||
m1 = (struct btf_param *)(t1 + 1);
|
m1 = btf_params(t1);
|
||||||
m2 = (struct btf_param *)(t2 + 1);
|
m2 = btf_params(t2);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
if (m1->name_off != m2->name_off)
|
if (m1->name_off != m2->name_off)
|
||||||
return false;
|
return false;
|
||||||
@@ -2028,7 +2073,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
__u32 cand_id;
|
__u32 cand_id;
|
||||||
long h;
|
long h;
|
||||||
|
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_CONST:
|
case BTF_KIND_CONST:
|
||||||
case BTF_KIND_VOLATILE:
|
case BTF_KIND_VOLATILE:
|
||||||
case BTF_KIND_RESTRICT:
|
case BTF_KIND_RESTRICT:
|
||||||
@@ -2141,13 +2186,13 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
|
|||||||
{
|
{
|
||||||
__u32 orig_type_id = type_id;
|
__u32 orig_type_id = type_id;
|
||||||
|
|
||||||
if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
|
if (!btf_is_fwd(d->btf->types[type_id]))
|
||||||
return type_id;
|
return type_id;
|
||||||
|
|
||||||
while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
|
while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
|
||||||
type_id = d->map[type_id];
|
type_id = d->map[type_id];
|
||||||
|
|
||||||
if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
|
if (!btf_is_fwd(d->btf->types[type_id]))
|
||||||
return type_id;
|
return type_id;
|
||||||
|
|
||||||
return orig_type_id;
|
return orig_type_id;
|
||||||
@@ -2156,7 +2201,7 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
|
|||||||
|
|
||||||
static inline __u16 btf_fwd_kind(struct btf_type *t)
|
static inline __u16 btf_fwd_kind(struct btf_type *t)
|
||||||
{
|
{
|
||||||
return BTF_INFO_KFLAG(t->info) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
|
return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2277,8 +2322,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
|
|
||||||
cand_type = d->btf->types[cand_id];
|
cand_type = d->btf->types[cand_id];
|
||||||
canon_type = d->btf->types[canon_id];
|
canon_type = d->btf->types[canon_id];
|
||||||
cand_kind = BTF_INFO_KIND(cand_type->info);
|
cand_kind = btf_kind(cand_type);
|
||||||
canon_kind = BTF_INFO_KIND(canon_type->info);
|
canon_kind = btf_kind(canon_type);
|
||||||
|
|
||||||
if (cand_type->name_off != canon_type->name_off)
|
if (cand_type->name_off != canon_type->name_off)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2327,12 +2372,12 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
||||||
|
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY: {
|
||||||
struct btf_array *cand_arr, *canon_arr;
|
const struct btf_array *cand_arr, *canon_arr;
|
||||||
|
|
||||||
if (!btf_compat_array(cand_type, canon_type))
|
if (!btf_compat_array(cand_type, canon_type))
|
||||||
return 0;
|
return 0;
|
||||||
cand_arr = (struct btf_array *)(cand_type + 1);
|
cand_arr = btf_array(cand_type);
|
||||||
canon_arr = (struct btf_array *)(canon_type + 1);
|
canon_arr = btf_array(canon_type);
|
||||||
eq = btf_dedup_is_equiv(d,
|
eq = btf_dedup_is_equiv(d,
|
||||||
cand_arr->index_type, canon_arr->index_type);
|
cand_arr->index_type, canon_arr->index_type);
|
||||||
if (eq <= 0)
|
if (eq <= 0)
|
||||||
@@ -2342,14 +2387,14 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
|
|
||||||
case BTF_KIND_STRUCT:
|
case BTF_KIND_STRUCT:
|
||||||
case BTF_KIND_UNION: {
|
case BTF_KIND_UNION: {
|
||||||
struct btf_member *cand_m, *canon_m;
|
const struct btf_member *cand_m, *canon_m;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
|
|
||||||
if (!btf_shallow_equal_struct(cand_type, canon_type))
|
if (!btf_shallow_equal_struct(cand_type, canon_type))
|
||||||
return 0;
|
return 0;
|
||||||
vlen = BTF_INFO_VLEN(cand_type->info);
|
vlen = btf_vlen(cand_type);
|
||||||
cand_m = (struct btf_member *)(cand_type + 1);
|
cand_m = btf_members(cand_type);
|
||||||
canon_m = (struct btf_member *)(canon_type + 1);
|
canon_m = btf_members(canon_type);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
|
eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
|
||||||
if (eq <= 0)
|
if (eq <= 0)
|
||||||
@@ -2362,7 +2407,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
struct btf_param *cand_p, *canon_p;
|
const struct btf_param *cand_p, *canon_p;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
|
|
||||||
if (!btf_compat_fnproto(cand_type, canon_type))
|
if (!btf_compat_fnproto(cand_type, canon_type))
|
||||||
@@ -2370,9 +2415,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
|||||||
eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
||||||
if (eq <= 0)
|
if (eq <= 0)
|
||||||
return eq;
|
return eq;
|
||||||
vlen = BTF_INFO_VLEN(cand_type->info);
|
vlen = btf_vlen(cand_type);
|
||||||
cand_p = (struct btf_param *)(cand_type + 1);
|
cand_p = btf_params(cand_type);
|
||||||
canon_p = (struct btf_param *)(canon_type + 1);
|
canon_p = btf_params(canon_type);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
|
eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
|
||||||
if (eq <= 0)
|
if (eq <= 0)
|
||||||
@@ -2427,8 +2472,8 @@ static void btf_dedup_merge_hypot_map(struct btf_dedup *d)
|
|||||||
targ_type_id = d->hypot_map[cand_type_id];
|
targ_type_id = d->hypot_map[cand_type_id];
|
||||||
t_id = resolve_type_id(d, targ_type_id);
|
t_id = resolve_type_id(d, targ_type_id);
|
||||||
c_id = resolve_type_id(d, cand_type_id);
|
c_id = resolve_type_id(d, cand_type_id);
|
||||||
t_kind = BTF_INFO_KIND(d->btf->types[t_id]->info);
|
t_kind = btf_kind(d->btf->types[t_id]);
|
||||||
c_kind = BTF_INFO_KIND(d->btf->types[c_id]->info);
|
c_kind = btf_kind(d->btf->types[c_id]);
|
||||||
/*
|
/*
|
||||||
* Resolve FWD into STRUCT/UNION.
|
* Resolve FWD into STRUCT/UNION.
|
||||||
* It's ok to resolve FWD into STRUCT/UNION that's not yet
|
* It's ok to resolve FWD into STRUCT/UNION that's not yet
|
||||||
@@ -2497,7 +2542,7 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
t = d->btf->types[type_id];
|
t = d->btf->types[type_id];
|
||||||
kind = BTF_INFO_KIND(t->info);
|
kind = btf_kind(t);
|
||||||
|
|
||||||
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
|
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2592,7 +2637,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
t = d->btf->types[type_id];
|
t = d->btf->types[type_id];
|
||||||
d->map[type_id] = BTF_IN_PROGRESS_ID;
|
d->map[type_id] = BTF_IN_PROGRESS_ID;
|
||||||
|
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_CONST:
|
case BTF_KIND_CONST:
|
||||||
case BTF_KIND_VOLATILE:
|
case BTF_KIND_VOLATILE:
|
||||||
case BTF_KIND_RESTRICT:
|
case BTF_KIND_RESTRICT:
|
||||||
@@ -2616,7 +2661,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY: {
|
||||||
struct btf_array *info = (struct btf_array *)(t + 1);
|
struct btf_array *info = btf_array(t);
|
||||||
|
|
||||||
ref_type_id = btf_dedup_ref_type(d, info->type);
|
ref_type_id = btf_dedup_ref_type(d, info->type);
|
||||||
if (ref_type_id < 0)
|
if (ref_type_id < 0)
|
||||||
@@ -2650,8 +2695,8 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
return ref_type_id;
|
return ref_type_id;
|
||||||
t->type = ref_type_id;
|
t->type = ref_type_id;
|
||||||
|
|
||||||
vlen = BTF_INFO_VLEN(t->info);
|
vlen = btf_vlen(t);
|
||||||
param = (struct btf_param *)(t + 1);
|
param = btf_params(t);
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
ref_type_id = btf_dedup_ref_type(d, param->type);
|
ref_type_id = btf_dedup_ref_type(d, param->type);
|
||||||
if (ref_type_id < 0)
|
if (ref_type_id < 0)
|
||||||
@@ -2791,7 +2836,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
struct btf_type *t = d->btf->types[type_id];
|
struct btf_type *t = d->btf->types[type_id];
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
switch (BTF_INFO_KIND(t->info)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
case BTF_KIND_ENUM:
|
case BTF_KIND_ENUM:
|
||||||
break;
|
break;
|
||||||
@@ -2811,7 +2856,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY: {
|
||||||
struct btf_array *arr_info = (struct btf_array *)(t + 1);
|
struct btf_array *arr_info = btf_array(t);
|
||||||
|
|
||||||
r = btf_dedup_remap_type_id(d, arr_info->type);
|
r = btf_dedup_remap_type_id(d, arr_info->type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@@ -2826,8 +2871,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
|
|
||||||
case BTF_KIND_STRUCT:
|
case BTF_KIND_STRUCT:
|
||||||
case BTF_KIND_UNION: {
|
case BTF_KIND_UNION: {
|
||||||
struct btf_member *member = (struct btf_member *)(t + 1);
|
struct btf_member *member = btf_members(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
r = btf_dedup_remap_type_id(d, member->type);
|
r = btf_dedup_remap_type_id(d, member->type);
|
||||||
@@ -2840,8 +2885,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
struct btf_param *param = (struct btf_param *)(t + 1);
|
struct btf_param *param = btf_params(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
r = btf_dedup_remap_type_id(d, t->type);
|
r = btf_dedup_remap_type_id(d, t->type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@@ -2859,8 +2904,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BTF_KIND_DATASEC: {
|
case BTF_KIND_DATASEC: {
|
||||||
struct btf_var_secinfo *var = (struct btf_var_secinfo *)(t + 1);
|
struct btf_var_secinfo *var = btf_var_secinfos(t);
|
||||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
for (i = 0; i < vlen; i++) {
|
for (i = 0; i < vlen; i++) {
|
||||||
r = btf_dedup_remap_type_id(d, var->type);
|
r = btf_dedup_remap_type_id(d, var->type);
|
||||||
@@ -2890,3 +2935,89 @@ static int btf_dedup_remap_types(struct btf_dedup *d)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct btf *btf_load_raw(const char *path)
|
||||||
|
{
|
||||||
|
struct btf *btf;
|
||||||
|
size_t read_cnt;
|
||||||
|
struct stat st;
|
||||||
|
void *data;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (stat(path, &st))
|
||||||
|
return ERR_PTR(-errno);
|
||||||
|
|
||||||
|
data = malloc(st.st_size);
|
||||||
|
if (!data)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
f = fopen(path, "rb");
|
||||||
|
if (!f) {
|
||||||
|
btf = ERR_PTR(-errno);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cnt = fread(data, 1, st.st_size, f);
|
||||||
|
fclose(f);
|
||||||
|
if (read_cnt < st.st_size) {
|
||||||
|
btf = ERR_PTR(-EBADF);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
btf = btf__new(data, read_cnt);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
free(data);
|
||||||
|
return btf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe few well-known locations for vmlinux kernel image and try to load BTF
|
||||||
|
* data out of it to use for target BTF.
|
||||||
|
*/
|
||||||
|
struct btf *libbpf_find_kernel_btf(void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *path_fmt;
|
||||||
|
bool raw_btf;
|
||||||
|
} locations[] = {
|
||||||
|
/* try canonical vmlinux BTF through sysfs first */
|
||||||
|
{ "/sys/kernel/btf/vmlinux", true /* raw BTF */ },
|
||||||
|
/* fall back to trying to find vmlinux ELF on disk otherwise */
|
||||||
|
{ "/boot/vmlinux-%1$s" },
|
||||||
|
{ "/lib/modules/%1$s/vmlinux-%1$s" },
|
||||||
|
{ "/lib/modules/%1$s/build/vmlinux" },
|
||||||
|
{ "/usr/lib/modules/%1$s/kernel/vmlinux" },
|
||||||
|
{ "/usr/lib/debug/boot/vmlinux-%1$s" },
|
||||||
|
{ "/usr/lib/debug/boot/vmlinux-%1$s.debug" },
|
||||||
|
{ "/usr/lib/debug/lib/modules/%1$s/vmlinux" },
|
||||||
|
};
|
||||||
|
char path[PATH_MAX + 1];
|
||||||
|
struct utsname buf;
|
||||||
|
struct btf *btf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
uname(&buf);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(locations); i++) {
|
||||||
|
snprintf(path, PATH_MAX, locations[i].path_fmt, buf.release);
|
||||||
|
|
||||||
|
if (access(path, R_OK))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (locations[i].raw_btf)
|
||||||
|
btf = btf_load_raw(path);
|
||||||
|
else
|
||||||
|
btf = btf__parse_elf(path, NULL);
|
||||||
|
|
||||||
|
pr_debug("loading kernel BTF '%s': %ld\n",
|
||||||
|
path, IS_ERR(btf) ? PTR_ERR(btf) : 0);
|
||||||
|
if (IS_ERR(btf))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return btf;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_warn("failed to find valid kernel BTF\n");
|
||||||
|
return ERR_PTR(-ESRCH);
|
||||||
|
}
|
||||||
|
|||||||
215
src/btf.h
215
src/btf.h
@@ -5,16 +5,15 @@
|
|||||||
#define __LIBBPF_BTF_H
|
#define __LIBBPF_BTF_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <linux/btf.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include "libbpf_common.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LIBBPF_API
|
|
||||||
#define LIBBPF_API __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BTF_ELF_SEC ".BTF"
|
#define BTF_ELF_SEC ".BTF"
|
||||||
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
||||||
#define MAPS_ELF_SEC ".maps"
|
#define MAPS_ELF_SEC ".maps"
|
||||||
@@ -57,6 +56,10 @@ struct btf_ext_header {
|
|||||||
__u32 func_info_len;
|
__u32 func_info_len;
|
||||||
__u32 line_info_off;
|
__u32 line_info_off;
|
||||||
__u32 line_info_len;
|
__u32 line_info_len;
|
||||||
|
|
||||||
|
/* optional part of .BTF.ext header */
|
||||||
|
__u32 field_reloc_off;
|
||||||
|
__u32 field_reloc_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBBPF_API void btf__free(struct btf *btf);
|
LIBBPF_API void btf__free(struct btf *btf);
|
||||||
@@ -67,11 +70,14 @@ LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
|||||||
LIBBPF_API int btf__load(struct btf *btf);
|
LIBBPF_API int btf__load(struct btf *btf);
|
||||||
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
||||||
const char *type_name);
|
const char *type_name);
|
||||||
|
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
|
||||||
|
const char *type_name, __u32 kind);
|
||||||
LIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);
|
LIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);
|
||||||
LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,
|
LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,
|
||||||
__u32 id);
|
__u32 id);
|
||||||
LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
||||||
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||||
|
LIBBPF_API int btf__align_of(const struct btf *btf, __u32 id);
|
||||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||||
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||||
@@ -96,6 +102,8 @@ LIBBPF_API int btf_ext__reloc_line_info(const struct btf *btf,
|
|||||||
LIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
LIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
LIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
LIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
|
|
||||||
|
LIBBPF_API struct btf *libbpf_find_kernel_btf(void);
|
||||||
|
|
||||||
struct btf_dedup_opts {
|
struct btf_dedup_opts {
|
||||||
unsigned int dedup_table_size;
|
unsigned int dedup_table_size;
|
||||||
bool dont_resolve_fwds;
|
bool dont_resolve_fwds;
|
||||||
@@ -120,6 +128,205 @@ LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
|||||||
|
|
||||||
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
||||||
|
|
||||||
|
struct btf_dump_emit_type_decl_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* optional field name for type declaration, e.g.:
|
||||||
|
* - struct my_struct <FNAME>
|
||||||
|
* - void (*<FNAME>)(int)
|
||||||
|
* - char (*<FNAME>)[123]
|
||||||
|
*/
|
||||||
|
const char *field_name;
|
||||||
|
/* extra indentation level (in number of tabs) to emit for multi-line
|
||||||
|
* type declarations (e.g., anonymous struct); applies for lines
|
||||||
|
* starting from the second one (first line is assumed to have
|
||||||
|
* necessary indentation already
|
||||||
|
*/
|
||||||
|
int indent_level;
|
||||||
|
};
|
||||||
|
#define btf_dump_emit_type_decl_opts__last_field indent_level
|
||||||
|
|
||||||
|
LIBBPF_API int
|
||||||
|
btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
||||||
|
const struct btf_dump_emit_type_decl_opts *opts);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A set of helpers for easier BTF types handling
|
||||||
|
*/
|
||||||
|
static inline __u16 btf_kind(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_KIND(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u16 btf_vlen(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_VLEN(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_kflag(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INFO_KFLAG(t->info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_int(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_ptr(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_array(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_struct(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_STRUCT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_union(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_UNION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_composite(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
__u16 kind = btf_kind(t);
|
||||||
|
|
||||||
|
return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_enum(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_ENUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_fwd(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FWD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_typedef(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_TYPEDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_volatile(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_VOLATILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_const(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_CONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_restrict(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_RESTRICT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_mod(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
__u16 kind = btf_kind(t);
|
||||||
|
|
||||||
|
return kind == BTF_KIND_VOLATILE ||
|
||||||
|
kind == BTF_KIND_CONST ||
|
||||||
|
kind == BTF_KIND_RESTRICT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_func(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_func_proto(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_FUNC_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_var(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool btf_is_datasec(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return btf_kind(t) == BTF_KIND_DATASEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_offset(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_OFFSET(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u8 btf_int_bits(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return BTF_INT_BITS(*(__u32 *)(t + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_array *btf_array(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_array *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_enum *btf_enum(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_enum *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_member *btf_members(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_member *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get bit offset of a member with specified index. */
|
||||||
|
static inline __u32 btf_member_bit_offset(const struct btf_type *t,
|
||||||
|
__u32 member_idx)
|
||||||
|
{
|
||||||
|
const struct btf_member *m = btf_members(t) + member_idx;
|
||||||
|
bool kflag = btf_kflag(t);
|
||||||
|
|
||||||
|
return kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Get bitfield size of a member, assuming t is BTF_KIND_STRUCT or
|
||||||
|
* BTF_KIND_UNION. If member is not a bitfield, zero is returned.
|
||||||
|
*/
|
||||||
|
static inline __u32 btf_member_bitfield_size(const struct btf_type *t,
|
||||||
|
__u32 member_idx)
|
||||||
|
{
|
||||||
|
const struct btf_member *m = btf_members(t) + member_idx;
|
||||||
|
bool kflag = btf_kflag(t);
|
||||||
|
|
||||||
|
return kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_param *btf_params(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_param *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_var *btf_var(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_var *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct btf_var_secinfo *
|
||||||
|
btf_var_secinfos(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (struct btf_var_secinfo *)(t + 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
358
src/btf_dump.c
358
src/btf_dump.c
@@ -18,6 +18,9 @@
|
|||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
static const char PREFIXES[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
static const char PREFIXES[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
||||||
static const size_t PREFIX_CNT = sizeof(PREFIXES) - 1;
|
static const size_t PREFIX_CNT = sizeof(PREFIXES) - 1;
|
||||||
|
|
||||||
@@ -48,6 +51,8 @@ struct btf_dump_type_aux_state {
|
|||||||
__u8 fwd_emitted: 1;
|
__u8 fwd_emitted: 1;
|
||||||
/* whether unique non-duplicate name was already assigned */
|
/* whether unique non-duplicate name was already assigned */
|
||||||
__u8 name_resolved: 1;
|
__u8 name_resolved: 1;
|
||||||
|
/* whether type is referenced from any other type */
|
||||||
|
__u8 referenced: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btf_dump {
|
struct btf_dump {
|
||||||
@@ -100,21 +105,6 @@ static bool str_equal_fn(const void *a, const void *b, void *ctx)
|
|||||||
return strcmp(a, b) == 0;
|
return strcmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __u16 btf_kind_of(const struct btf_type *t)
|
|
||||||
{
|
|
||||||
return BTF_INFO_KIND(t->info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __u16 btf_vlen_of(const struct btf_type *t)
|
|
||||||
{
|
|
||||||
return BTF_INFO_VLEN(t->info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool btf_kflag_of(const struct btf_type *t)
|
|
||||||
{
|
|
||||||
return BTF_INFO_KFLAG(t->info);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
return btf__name_by_offset(d->btf, name_off);
|
return btf__name_by_offset(d->btf, name_off);
|
||||||
@@ -129,6 +119,8 @@ static void btf_dump_printf(const struct btf_dump *d, const char *fmt, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btf_dump_mark_referenced(struct btf_dump *d);
|
||||||
|
|
||||||
struct btf_dump *btf_dump__new(const struct btf *btf,
|
struct btf_dump *btf_dump__new(const struct btf *btf,
|
||||||
const struct btf_ext *btf_ext,
|
const struct btf_ext *btf_ext,
|
||||||
const struct btf_dump_opts *opts,
|
const struct btf_dump_opts *opts,
|
||||||
@@ -150,18 +142,40 @@ struct btf_dump *btf_dump__new(const struct btf *btf,
|
|||||||
if (IS_ERR(d->type_names)) {
|
if (IS_ERR(d->type_names)) {
|
||||||
err = PTR_ERR(d->type_names);
|
err = PTR_ERR(d->type_names);
|
||||||
d->type_names = NULL;
|
d->type_names = NULL;
|
||||||
btf_dump__free(d);
|
goto err;
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
}
|
||||||
d->ident_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
|
d->ident_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
|
||||||
if (IS_ERR(d->ident_names)) {
|
if (IS_ERR(d->ident_names)) {
|
||||||
err = PTR_ERR(d->ident_names);
|
err = PTR_ERR(d->ident_names);
|
||||||
d->ident_names = NULL;
|
d->ident_names = NULL;
|
||||||
btf_dump__free(d);
|
goto err;
|
||||||
return ERR_PTR(err);
|
}
|
||||||
|
d->type_states = calloc(1 + btf__get_nr_types(d->btf),
|
||||||
|
sizeof(d->type_states[0]));
|
||||||
|
if (!d->type_states) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
d->cached_names = calloc(1 + btf__get_nr_types(d->btf),
|
||||||
|
sizeof(d->cached_names[0]));
|
||||||
|
if (!d->cached_names) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VOID is special */
|
||||||
|
d->type_states[0].order_state = ORDERED;
|
||||||
|
d->type_states[0].emit_state = EMITTED;
|
||||||
|
|
||||||
|
/* eagerly determine referenced types for anon enums */
|
||||||
|
err = btf_dump_mark_referenced(d);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
|
err:
|
||||||
|
btf_dump__free(d);
|
||||||
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void btf_dump__free(struct btf_dump *d)
|
void btf_dump__free(struct btf_dump *d)
|
||||||
@@ -214,22 +228,6 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
|||||||
if (id > btf__get_nr_types(d->btf))
|
if (id > btf__get_nr_types(d->btf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* type states are lazily allocated, as they might not be needed */
|
|
||||||
if (!d->type_states) {
|
|
||||||
d->type_states = calloc(1 + btf__get_nr_types(d->btf),
|
|
||||||
sizeof(d->type_states[0]));
|
|
||||||
if (!d->type_states)
|
|
||||||
return -ENOMEM;
|
|
||||||
d->cached_names = calloc(1 + btf__get_nr_types(d->btf),
|
|
||||||
sizeof(d->cached_names[0]));
|
|
||||||
if (!d->cached_names)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* VOID is special */
|
|
||||||
d->type_states[0].order_state = ORDERED;
|
|
||||||
d->type_states[0].emit_state = EMITTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->emit_queue_cnt = 0;
|
d->emit_queue_cnt = 0;
|
||||||
err = btf_dump_order_type(d, id, false);
|
err = btf_dump_order_type(d, id, false);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -241,6 +239,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark all types that are referenced from any other type. This is used to
|
||||||
|
* determine top-level anonymous enums that need to be emitted as an
|
||||||
|
* independent type declarations.
|
||||||
|
* Anonymous enums come in two flavors: either embedded in a struct's field
|
||||||
|
* definition, in which case they have to be declared inline as part of field
|
||||||
|
* type declaration; or as a top-level anonymous enum, typically used for
|
||||||
|
* declaring global constants. It's impossible to distinguish between two
|
||||||
|
* without knowning whether given enum type was referenced from other type:
|
||||||
|
* top-level anonymous enum won't be referenced by anything, while embedded
|
||||||
|
* one will.
|
||||||
|
*/
|
||||||
|
static int btf_dump_mark_referenced(struct btf_dump *d)
|
||||||
|
{
|
||||||
|
int i, j, n = btf__get_nr_types(d->btf);
|
||||||
|
const struct btf_type *t;
|
||||||
|
__u16 vlen;
|
||||||
|
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
t = btf__type_by_id(d->btf, i);
|
||||||
|
vlen = btf_vlen(t);
|
||||||
|
|
||||||
|
switch (btf_kind(t)) {
|
||||||
|
case BTF_KIND_INT:
|
||||||
|
case BTF_KIND_ENUM:
|
||||||
|
case BTF_KIND_FWD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTF_KIND_VOLATILE:
|
||||||
|
case BTF_KIND_CONST:
|
||||||
|
case BTF_KIND_RESTRICT:
|
||||||
|
case BTF_KIND_PTR:
|
||||||
|
case BTF_KIND_TYPEDEF:
|
||||||
|
case BTF_KIND_FUNC:
|
||||||
|
case BTF_KIND_VAR:
|
||||||
|
d->type_states[t->type].referenced = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTF_KIND_ARRAY: {
|
||||||
|
const struct btf_array *a = btf_array(t);
|
||||||
|
|
||||||
|
d->type_states[a->index_type].referenced = 1;
|
||||||
|
d->type_states[a->type].referenced = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BTF_KIND_STRUCT:
|
||||||
|
case BTF_KIND_UNION: {
|
||||||
|
const struct btf_member *m = btf_members(t);
|
||||||
|
|
||||||
|
for (j = 0; j < vlen; j++, m++)
|
||||||
|
d->type_states[m->type].referenced = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
|
const struct btf_param *p = btf_params(t);
|
||||||
|
|
||||||
|
for (j = 0; j < vlen; j++, p++)
|
||||||
|
d->type_states[p->type].referenced = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BTF_KIND_DATASEC: {
|
||||||
|
const struct btf_var_secinfo *v = btf_var_secinfos(t);
|
||||||
|
|
||||||
|
for (j = 0; j < vlen; j++, v++)
|
||||||
|
d->type_states[v->type].referenced = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
|
static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
|
||||||
{
|
{
|
||||||
__u32 *new_queue;
|
__u32 *new_queue;
|
||||||
@@ -349,7 +420,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
*/
|
*/
|
||||||
struct btf_dump_type_aux_state *tstate = &d->type_states[id];
|
struct btf_dump_type_aux_state *tstate = &d->type_states[id];
|
||||||
const struct btf_type *t;
|
const struct btf_type *t;
|
||||||
__u16 kind, vlen;
|
__u16 vlen;
|
||||||
int err, i;
|
int err, i;
|
||||||
|
|
||||||
/* return true, letting typedefs know that it's ok to be emitted */
|
/* return true, letting typedefs know that it's ok to be emitted */
|
||||||
@@ -357,18 +428,16 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
t = btf__type_by_id(d->btf, id);
|
t = btf__type_by_id(d->btf, id);
|
||||||
kind = btf_kind_of(t);
|
|
||||||
|
|
||||||
if (tstate->order_state == ORDERING) {
|
if (tstate->order_state == ORDERING) {
|
||||||
/* type loop, but resolvable through fwd declaration */
|
/* type loop, but resolvable through fwd declaration */
|
||||||
if ((kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION) &&
|
if (btf_is_composite(t) && through_ptr && t->name_off != 0)
|
||||||
through_ptr && t->name_off != 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
pr_warning("unsatisfiable type cycle, id:[%u]\n", id);
|
pr_warn("unsatisfiable type cycle, id:[%u]\n", id);
|
||||||
return -ELOOP;
|
return -ELOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (kind) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
tstate->order_state = ORDERED;
|
tstate->order_state = ORDERED;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -378,14 +447,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
tstate->order_state = ORDERED;
|
tstate->order_state = ORDERED;
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY:
|
||||||
const struct btf_array *a = (void *)(t + 1);
|
return btf_dump_order_type(d, btf_array(t)->type, through_ptr);
|
||||||
|
|
||||||
return btf_dump_order_type(d, a->type, through_ptr);
|
|
||||||
}
|
|
||||||
case BTF_KIND_STRUCT:
|
case BTF_KIND_STRUCT:
|
||||||
case BTF_KIND_UNION: {
|
case BTF_KIND_UNION: {
|
||||||
const struct btf_member *m = (void *)(t + 1);
|
const struct btf_member *m = btf_members(t);
|
||||||
/*
|
/*
|
||||||
* struct/union is part of strong link, only if it's embedded
|
* struct/union is part of strong link, only if it's embedded
|
||||||
* (so no ptr in a path) or it's anonymous (so has to be
|
* (so no ptr in a path) or it's anonymous (so has to be
|
||||||
@@ -396,7 +463,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
|
|
||||||
tstate->order_state = ORDERING;
|
tstate->order_state = ORDERING;
|
||||||
|
|
||||||
vlen = btf_vlen_of(t);
|
vlen = btf_vlen(t);
|
||||||
for (i = 0; i < vlen; i++, m++) {
|
for (i = 0; i < vlen; i++, m++) {
|
||||||
err = btf_dump_order_type(d, m->type, false);
|
err = btf_dump_order_type(d, m->type, false);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -414,7 +481,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
}
|
}
|
||||||
case BTF_KIND_ENUM:
|
case BTF_KIND_ENUM:
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
if (t->name_off != 0) {
|
/*
|
||||||
|
* non-anonymous or non-referenced enums are top-level
|
||||||
|
* declarations and should be emitted. Same logic can be
|
||||||
|
* applied to FWDs, it won't hurt anyways.
|
||||||
|
*/
|
||||||
|
if (t->name_off != 0 || !tstate->referenced) {
|
||||||
err = btf_dump_add_emit_queue_id(d, id);
|
err = btf_dump_add_emit_queue_id(d, id);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@@ -447,7 +519,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
return btf_dump_order_type(d, t->type, through_ptr);
|
return btf_dump_order_type(d, t->type, through_ptr);
|
||||||
|
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
const struct btf_param *p = (void *)(t + 1);
|
const struct btf_param *p = btf_params(t);
|
||||||
bool is_strong;
|
bool is_strong;
|
||||||
|
|
||||||
err = btf_dump_order_type(d, t->type, through_ptr);
|
err = btf_dump_order_type(d, t->type, through_ptr);
|
||||||
@@ -455,7 +527,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
|||||||
return err;
|
return err;
|
||||||
is_strong = err > 0;
|
is_strong = err > 0;
|
||||||
|
|
||||||
vlen = btf_vlen_of(t);
|
vlen = btf_vlen(t);
|
||||||
for (i = 0; i < vlen; i++, p++) {
|
for (i = 0; i < vlen; i++, p++) {
|
||||||
err = btf_dump_order_type(d, p->type, through_ptr);
|
err = btf_dump_order_type(d, p->type, through_ptr);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -553,12 +625,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
t = btf__type_by_id(d->btf, id);
|
t = btf__type_by_id(d->btf, id);
|
||||||
kind = btf_kind_of(t);
|
kind = btf_kind(t);
|
||||||
|
|
||||||
if (top_level_def && t->name_off == 0) {
|
|
||||||
pr_warning("unexpected nameless definition, id:[%u]\n", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tstate->emit_state == EMITTING) {
|
if (tstate->emit_state == EMITTING) {
|
||||||
if (tstate->fwd_emitted)
|
if (tstate->fwd_emitted)
|
||||||
@@ -574,8 +641,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
if (id == cont_id)
|
if (id == cont_id)
|
||||||
return;
|
return;
|
||||||
if (t->name_off == 0) {
|
if (t->name_off == 0) {
|
||||||
pr_warning("anonymous struct/union loop, id:[%u]\n",
|
pr_warn("anonymous struct/union loop, id:[%u]\n",
|
||||||
id);
|
id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
btf_dump_emit_struct_fwd(d, id, t);
|
btf_dump_emit_struct_fwd(d, id, t);
|
||||||
@@ -618,12 +685,9 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
case BTF_KIND_RESTRICT:
|
case BTF_KIND_RESTRICT:
|
||||||
btf_dump_emit_type(d, t->type, cont_id);
|
btf_dump_emit_type(d, t->type, cont_id);
|
||||||
break;
|
break;
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY:
|
||||||
const struct btf_array *a = (void *)(t + 1);
|
btf_dump_emit_type(d, btf_array(t)->type, cont_id);
|
||||||
|
|
||||||
btf_dump_emit_type(d, a->type, cont_id);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
btf_dump_emit_fwd_def(d, id, t);
|
btf_dump_emit_fwd_def(d, id, t);
|
||||||
btf_dump_printf(d, ";\n\n");
|
btf_dump_printf(d, ";\n\n");
|
||||||
@@ -656,8 +720,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
* applicable
|
* applicable
|
||||||
*/
|
*/
|
||||||
if (top_level_def || t->name_off == 0) {
|
if (top_level_def || t->name_off == 0) {
|
||||||
const struct btf_member *m = (void *)(t + 1);
|
const struct btf_member *m = btf_members(t);
|
||||||
__u16 vlen = btf_vlen_of(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
int i, new_cont_id;
|
int i, new_cont_id;
|
||||||
|
|
||||||
new_cont_id = t->name_off == 0 ? cont_id : id;
|
new_cont_id = t->name_off == 0 ? cont_id : id;
|
||||||
@@ -678,8 +742,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
const struct btf_param *p = (void *)(t + 1);
|
const struct btf_param *p = btf_params(t);
|
||||||
__u16 vlen = btf_vlen_of(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
btf_dump_emit_type(d, t->type, cont_id);
|
btf_dump_emit_type(d, t->type, cont_id);
|
||||||
@@ -693,65 +757,25 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btf_align_of(const struct btf *btf, __u32 id)
|
|
||||||
{
|
|
||||||
const struct btf_type *t = btf__type_by_id(btf, id);
|
|
||||||
__u16 kind = btf_kind_of(t);
|
|
||||||
|
|
||||||
switch (kind) {
|
|
||||||
case BTF_KIND_INT:
|
|
||||||
case BTF_KIND_ENUM:
|
|
||||||
return min(sizeof(void *), t->size);
|
|
||||||
case BTF_KIND_PTR:
|
|
||||||
return sizeof(void *);
|
|
||||||
case BTF_KIND_TYPEDEF:
|
|
||||||
case BTF_KIND_VOLATILE:
|
|
||||||
case BTF_KIND_CONST:
|
|
||||||
case BTF_KIND_RESTRICT:
|
|
||||||
return btf_align_of(btf, t->type);
|
|
||||||
case BTF_KIND_ARRAY: {
|
|
||||||
const struct btf_array *a = (void *)(t + 1);
|
|
||||||
|
|
||||||
return btf_align_of(btf, a->type);
|
|
||||||
}
|
|
||||||
case BTF_KIND_STRUCT:
|
|
||||||
case BTF_KIND_UNION: {
|
|
||||||
const struct btf_member *m = (void *)(t + 1);
|
|
||||||
__u16 vlen = btf_vlen_of(t);
|
|
||||||
int i, align = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < vlen; i++, m++)
|
|
||||||
align = max(align, btf_align_of(btf, m->type));
|
|
||||||
|
|
||||||
return align;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
pr_warning("unsupported BTF_KIND:%u\n", btf_kind_of(t));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
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 align, i, bit_sz;
|
||||||
__u16 vlen;
|
__u16 vlen;
|
||||||
bool kflag;
|
|
||||||
|
|
||||||
align = btf_align_of(btf, id);
|
align = btf__align_of(btf, id);
|
||||||
/* size of a non-packed struct has to be a multiple of its alignment*/
|
/* size of a non-packed struct has to be a multiple of its alignment*/
|
||||||
if (t->size % align)
|
if (align && t->size % align)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
m = (void *)(t + 1);
|
m = btf_members(t);
|
||||||
kflag = btf_kflag_of(t);
|
vlen = btf_vlen(t);
|
||||||
vlen = btf_vlen_of(t);
|
|
||||||
/* all non-bitfield fields have to be naturally aligned */
|
/* all non-bitfield fields have to be naturally aligned */
|
||||||
for (i = 0; i < vlen; i++, m++) {
|
for (i = 0; i < vlen; i++, m++) {
|
||||||
align = btf_align_of(btf, m->type);
|
align = btf__align_of(btf, m->type);
|
||||||
bit_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
bit_sz = btf_member_bitfield_size(t, i);
|
||||||
if (bit_sz == 0 && m->offset % (8 * align) != 0)
|
if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,7 +831,7 @@ static void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,
|
|||||||
const struct btf_type *t)
|
const struct btf_type *t)
|
||||||
{
|
{
|
||||||
btf_dump_printf(d, "%s %s",
|
btf_dump_printf(d, "%s %s",
|
||||||
btf_kind_of(t) == BTF_KIND_STRUCT ? "struct" : "union",
|
btf_is_struct(t) ? "struct" : "union",
|
||||||
btf_dump_type_name(d, id));
|
btf_dump_type_name(d, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,14 +840,12 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
|||||||
const struct btf_type *t,
|
const struct btf_type *t,
|
||||||
int lvl)
|
int lvl)
|
||||||
{
|
{
|
||||||
const struct btf_member *m = (void *)(t + 1);
|
const struct btf_member *m = btf_members(t);
|
||||||
bool kflag = btf_kflag_of(t), is_struct;
|
bool is_struct = btf_is_struct(t);
|
||||||
int align, i, packed, off = 0;
|
int align, i, packed, off = 0;
|
||||||
__u16 vlen = btf_vlen_of(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
|
|
||||||
is_struct = btf_kind_of(t) == BTF_KIND_STRUCT;
|
|
||||||
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
||||||
align = packed ? 1 : btf_align_of(d->btf, id);
|
|
||||||
|
|
||||||
btf_dump_printf(d, "%s%s%s {",
|
btf_dump_printf(d, "%s%s%s {",
|
||||||
is_struct ? "struct" : "union",
|
is_struct ? "struct" : "union",
|
||||||
@@ -835,9 +857,9 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
|||||||
int m_off, m_sz;
|
int m_off, m_sz;
|
||||||
|
|
||||||
fname = btf_name_of(d, m->name_off);
|
fname = btf_name_of(d, m->name_off);
|
||||||
m_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
m_sz = btf_member_bitfield_size(t, i);
|
||||||
m_off = kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
|
m_off = btf_member_bit_offset(t, i);
|
||||||
align = packed ? 1 : btf_align_of(d->btf, m->type);
|
align = packed ? 1 : btf__align_of(d->btf, m->type);
|
||||||
|
|
||||||
btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
|
btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
|
||||||
btf_dump_printf(d, "\n%s", pfx(lvl + 1));
|
btf_dump_printf(d, "\n%s", pfx(lvl + 1));
|
||||||
@@ -853,6 +875,13 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
|||||||
btf_dump_printf(d, ";");
|
btf_dump_printf(d, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pad at the end, if necessary */
|
||||||
|
if (is_struct) {
|
||||||
|
align = packed ? 1 : btf__align_of(d->btf, id);
|
||||||
|
btf_dump_emit_bit_padding(d, off, t->size * 8, 0, align,
|
||||||
|
lvl + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (vlen)
|
if (vlen)
|
||||||
btf_dump_printf(d, "\n");
|
btf_dump_printf(d, "\n");
|
||||||
btf_dump_printf(d, "%s}", pfx(lvl));
|
btf_dump_printf(d, "%s}", pfx(lvl));
|
||||||
@@ -870,8 +899,8 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
|||||||
const struct btf_type *t,
|
const struct btf_type *t,
|
||||||
int lvl)
|
int lvl)
|
||||||
{
|
{
|
||||||
const struct btf_enum *v = (void *)(t+1);
|
const struct btf_enum *v = btf_enum(t);
|
||||||
__u16 vlen = btf_vlen_of(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
const char *name;
|
const char *name;
|
||||||
size_t dup_cnt;
|
size_t dup_cnt;
|
||||||
int i;
|
int i;
|
||||||
@@ -905,7 +934,7 @@ static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
|||||||
{
|
{
|
||||||
const char *name = btf_dump_type_name(d, id);
|
const char *name = btf_dump_type_name(d, id);
|
||||||
|
|
||||||
if (btf_kflag_of(t))
|
if (btf_kflag(t))
|
||||||
btf_dump_printf(d, "union %s", name);
|
btf_dump_printf(d, "union %s", name);
|
||||||
else
|
else
|
||||||
btf_dump_printf(d, "struct %s", name);
|
btf_dump_printf(d, "struct %s", name);
|
||||||
@@ -916,6 +945,17 @@ static void btf_dump_emit_typedef_def(struct btf_dump *d, __u32 id,
|
|||||||
{
|
{
|
||||||
const char *name = btf_dump_ident_name(d, id);
|
const char *name = btf_dump_ident_name(d, id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Old GCC versions are emitting invalid typedef for __gnuc_va_list
|
||||||
|
* pointing to VOID. This generates warnings from btf_dump() and
|
||||||
|
* results in uncompilable header file, so we are fixing it up here
|
||||||
|
* with valid typedef into __builtin_va_list.
|
||||||
|
*/
|
||||||
|
if (t->type == 0 && strcmp(name, "__gnuc_va_list") == 0) {
|
||||||
|
btf_dump_printf(d, "typedef __builtin_va_list __gnuc_va_list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
btf_dump_printf(d, "typedef ");
|
btf_dump_printf(d, "typedef ");
|
||||||
btf_dump_emit_type_decl(d, t->type, name, lvl);
|
btf_dump_emit_type_decl(d, t->type, name, lvl);
|
||||||
}
|
}
|
||||||
@@ -981,13 +1021,27 @@ static int btf_dump_push_decl_stack_id(struct btf_dump *d, __u32 id)
|
|||||||
* of a stack frame. Some care is required to "pop" stack frames after
|
* of a stack frame. Some care is required to "pop" stack frames after
|
||||||
* processing type declaration chain.
|
* processing type declaration chain.
|
||||||
*/
|
*/
|
||||||
|
int btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
||||||
|
const struct btf_dump_emit_type_decl_opts *opts)
|
||||||
|
{
|
||||||
|
const char *fname;
|
||||||
|
int lvl;
|
||||||
|
|
||||||
|
if (!OPTS_VALID(opts, btf_dump_emit_type_decl_opts))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
fname = OPTS_GET(opts, field_name, NULL);
|
||||||
|
lvl = OPTS_GET(opts, indent_level, 0);
|
||||||
|
btf_dump_emit_type_decl(d, id, fname, lvl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||||
const char *fname, int lvl)
|
const char *fname, int lvl)
|
||||||
{
|
{
|
||||||
struct id_stack decl_stack;
|
struct id_stack decl_stack;
|
||||||
const struct btf_type *t;
|
const struct btf_type *t;
|
||||||
int err, stack_start;
|
int err, stack_start;
|
||||||
__u16 kind;
|
|
||||||
|
|
||||||
stack_start = d->decl_stack_cnt;
|
stack_start = d->decl_stack_cnt;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -998,7 +1052,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
|||||||
* chain, restore stack, emit warning, and try to
|
* chain, restore stack, emit warning, and try to
|
||||||
* proceed nevertheless
|
* proceed nevertheless
|
||||||
*/
|
*/
|
||||||
pr_warning("not enough memory for decl stack:%d", err);
|
pr_warn("not enough memory for decl stack:%d", err);
|
||||||
d->decl_stack_cnt = stack_start;
|
d->decl_stack_cnt = stack_start;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1008,8 +1062,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
t = btf__type_by_id(d->btf, id);
|
t = btf__type_by_id(d->btf, id);
|
||||||
kind = btf_kind_of(t);
|
switch (btf_kind(t)) {
|
||||||
switch (kind) {
|
|
||||||
case BTF_KIND_PTR:
|
case BTF_KIND_PTR:
|
||||||
case BTF_KIND_VOLATILE:
|
case BTF_KIND_VOLATILE:
|
||||||
case BTF_KIND_CONST:
|
case BTF_KIND_CONST:
|
||||||
@@ -1017,12 +1070,9 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
|||||||
case BTF_KIND_FUNC_PROTO:
|
case BTF_KIND_FUNC_PROTO:
|
||||||
id = t->type;
|
id = t->type;
|
||||||
break;
|
break;
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY:
|
||||||
const struct btf_array *a = (void *)(t + 1);
|
id = btf_array(t)->type;
|
||||||
|
|
||||||
id = a->type;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
case BTF_KIND_ENUM:
|
case BTF_KIND_ENUM:
|
||||||
case BTF_KIND_FWD:
|
case BTF_KIND_FWD:
|
||||||
@@ -1031,8 +1081,8 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
|||||||
case BTF_KIND_TYPEDEF:
|
case BTF_KIND_TYPEDEF:
|
||||||
goto done;
|
goto done;
|
||||||
default:
|
default:
|
||||||
pr_warning("unexpected type in decl chain, kind:%u, id:[%u]\n",
|
pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n",
|
||||||
kind, id);
|
btf_kind(t), id);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1120,7 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
|
|||||||
id = decl_stack->ids[decl_stack->cnt - 1];
|
id = decl_stack->ids[decl_stack->cnt - 1];
|
||||||
t = btf__type_by_id(d->btf, id);
|
t = btf__type_by_id(d->btf, id);
|
||||||
|
|
||||||
switch (btf_kind_of(t)) {
|
switch (btf_kind(t)) {
|
||||||
case BTF_KIND_VOLATILE:
|
case BTF_KIND_VOLATILE:
|
||||||
btf_dump_printf(d, "volatile ");
|
btf_dump_printf(d, "volatile ");
|
||||||
break;
|
break;
|
||||||
@@ -1087,20 +1137,6 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_is_mod_kind(const struct btf *btf, __u32 id)
|
|
||||||
{
|
|
||||||
const struct btf_type *t = btf__type_by_id(btf, id);
|
|
||||||
|
|
||||||
switch (btf_kind_of(t)) {
|
|
||||||
case BTF_KIND_VOLATILE:
|
|
||||||
case BTF_KIND_CONST:
|
|
||||||
case BTF_KIND_RESTRICT:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void btf_dump_emit_name(const struct btf_dump *d,
|
static void btf_dump_emit_name(const struct btf_dump *d,
|
||||||
const char *name, bool last_was_ptr)
|
const char *name, bool last_was_ptr)
|
||||||
{
|
{
|
||||||
@@ -1139,7 +1175,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
}
|
}
|
||||||
|
|
||||||
t = btf__type_by_id(d->btf, id);
|
t = btf__type_by_id(d->btf, id);
|
||||||
kind = btf_kind_of(t);
|
kind = btf_kind(t);
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case BTF_KIND_INT:
|
case BTF_KIND_INT:
|
||||||
@@ -1185,7 +1221,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
btf_dump_printf(d, " restrict");
|
btf_dump_printf(d, " restrict");
|
||||||
break;
|
break;
|
||||||
case BTF_KIND_ARRAY: {
|
case BTF_KIND_ARRAY: {
|
||||||
const struct btf_array *a = (void *)(t + 1);
|
const struct btf_array *a = btf_array(t);
|
||||||
const struct btf_type *next_t;
|
const struct btf_type *next_t;
|
||||||
__u32 next_id;
|
__u32 next_id;
|
||||||
bool multidim;
|
bool multidim;
|
||||||
@@ -1201,7 +1237,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
*/
|
*/
|
||||||
while (decls->cnt) {
|
while (decls->cnt) {
|
||||||
next_id = decls->ids[decls->cnt - 1];
|
next_id = decls->ids[decls->cnt - 1];
|
||||||
if (btf_is_mod_kind(d->btf, next_id))
|
next_t = btf__type_by_id(d->btf, next_id);
|
||||||
|
if (btf_is_mod(next_t))
|
||||||
decls->cnt--;
|
decls->cnt--;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -1213,8 +1250,9 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_id = decls->ids[decls->cnt - 1];
|
||||||
next_t = btf__type_by_id(d->btf, next_id);
|
next_t = btf__type_by_id(d->btf, next_id);
|
||||||
multidim = btf_kind_of(next_t) == BTF_KIND_ARRAY;
|
multidim = btf_is_array(next_t);
|
||||||
/* we need space if we have named non-pointer */
|
/* we need space if we have named non-pointer */
|
||||||
if (fname[0] && !last_was_ptr)
|
if (fname[0] && !last_was_ptr)
|
||||||
btf_dump_printf(d, " ");
|
btf_dump_printf(d, " ");
|
||||||
@@ -1228,8 +1266,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case BTF_KIND_FUNC_PROTO: {
|
case BTF_KIND_FUNC_PROTO: {
|
||||||
const struct btf_param *p = (void *)(t + 1);
|
const struct btf_param *p = btf_params(t);
|
||||||
__u16 vlen = btf_vlen_of(t);
|
__u16 vlen = btf_vlen(t);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
btf_dump_emit_mods(d, decls);
|
btf_dump_emit_mods(d, decls);
|
||||||
@@ -1270,8 +1308,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
pr_warning("unexpected type in decl chain, kind:%u, id:[%u]\n",
|
pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n",
|
||||||
kind, id);
|
kind, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
/* start with 4 buckets */
|
/* start with 4 buckets */
|
||||||
#define HASHMAP_MIN_CAP_BITS 2
|
#define HASHMAP_MIN_CAP_BITS 2
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#include <bits/wordsize.h>
|
||||||
|
#else
|
||||||
|
#include <bits/reg.h>
|
||||||
|
#endif
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
static inline size_t hash_bits(size_t h, int bits)
|
static inline size_t hash_bits(size_t h, int bits)
|
||||||
|
|||||||
5200
src/libbpf.c
5200
src/libbpf.c
File diff suppressed because it is too large
Load Diff
169
src/libbpf.h
169
src/libbpf.h
@@ -17,14 +17,12 @@
|
|||||||
#include <sys/types.h> // for size_t
|
#include <sys/types.h> // for size_t
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
|
|
||||||
|
#include "libbpf_common.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LIBBPF_API
|
|
||||||
#define LIBBPF_API __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum libbpf_errno {
|
enum libbpf_errno {
|
||||||
__LIBBPF_ERRNO__START = 4000,
|
__LIBBPF_ERRNO__START = 4000,
|
||||||
|
|
||||||
@@ -57,7 +55,7 @@ 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);
|
||||||
|
|
||||||
LIBBPF_API void 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 */
|
||||||
struct bpf_object;
|
struct bpf_object;
|
||||||
@@ -67,18 +65,61 @@ struct bpf_object_open_attr {
|
|||||||
enum bpf_prog_type prog_type;
|
enum bpf_prog_type prog_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_object_open_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* object name override, if provided:
|
||||||
|
* - for object open from file, this will override setting object
|
||||||
|
* name from file path's base name;
|
||||||
|
* - for object open from memory buffer, this will specify an object
|
||||||
|
* name and will override default "<addr>-<buf-size>" name;
|
||||||
|
*/
|
||||||
|
const char *object_name;
|
||||||
|
/* parse map definitions non-strictly, allowing extra attributes/data */
|
||||||
|
bool relaxed_maps;
|
||||||
|
/* DEPRECATED: handle CO-RE relocations non-strictly, allowing failures.
|
||||||
|
* Value is ignored. Relocations always are processed non-strictly.
|
||||||
|
* Non-relocatable instructions are replaced with invalid ones to
|
||||||
|
* prevent accidental errors.
|
||||||
|
* */
|
||||||
|
bool relaxed_core_relocs;
|
||||||
|
/* maps that set the 'pinning' attribute in their definition will have
|
||||||
|
* their pin_path attribute set to a file in this directory, and be
|
||||||
|
* auto-pinned to that path on load; defaults to "/sys/fs/bpf".
|
||||||
|
*/
|
||||||
|
const char *pin_root_path;
|
||||||
|
__u32 attach_prog_fd;
|
||||||
|
/* Additional kernel config content that augments and overrides
|
||||||
|
* system Kconfig for CONFIG_xxx externs.
|
||||||
|
*/
|
||||||
|
const char *kconfig;
|
||||||
|
};
|
||||||
|
#define bpf_object_open_opts__last_field kconfig
|
||||||
|
|
||||||
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
||||||
LIBBPF_API struct bpf_object *
|
LIBBPF_API struct bpf_object *
|
||||||
|
bpf_object__open_file(const char *path, const struct bpf_object_open_opts *opts);
|
||||||
|
LIBBPF_API struct bpf_object *
|
||||||
|
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
|
||||||
|
const struct bpf_object_open_opts *opts);
|
||||||
|
|
||||||
|
/* deprecated bpf_object__open variants */
|
||||||
|
LIBBPF_API struct bpf_object *
|
||||||
|
bpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz,
|
||||||
|
const char *name);
|
||||||
|
LIBBPF_API struct bpf_object *
|
||||||
bpf_object__open_xattr(struct bpf_object_open_attr *attr);
|
bpf_object__open_xattr(struct bpf_object_open_attr *attr);
|
||||||
struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
|
|
||||||
int flags);
|
enum libbpf_pin_type {
|
||||||
LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
LIBBPF_PIN_NONE,
|
||||||
size_t obj_buf_sz,
|
/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
|
||||||
const char *name);
|
LIBBPF_PIN_BY_NAME,
|
||||||
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
};
|
||||||
__u32 *size);
|
|
||||||
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
/* pin_maps and unpin_maps can both be called with a NULL path, in which case
|
||||||
__u32 *off);
|
* they will use the pin_path attribute of each map (and ignore all maps that
|
||||||
|
* don't have a pin_path set).
|
||||||
|
*/
|
||||||
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);
|
||||||
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);
|
||||||
@@ -92,12 +133,14 @@ LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
|||||||
struct bpf_object_load_attr {
|
struct bpf_object_load_attr {
|
||||||
struct bpf_object *obj;
|
struct bpf_object *obj;
|
||||||
int log_level;
|
int log_level;
|
||||||
|
const char *target_btf_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Load/unload object into/from kernel */
|
/* Load/unload object into/from kernel */
|
||||||
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
||||||
LIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);
|
LIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);
|
||||||
LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
|
LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
|
||||||
|
|
||||||
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
||||||
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
||||||
|
|
||||||
@@ -108,6 +151,9 @@ LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj);
|
|||||||
LIBBPF_API struct bpf_program *
|
LIBBPF_API struct bpf_program *
|
||||||
bpf_object__find_program_by_title(const struct bpf_object *obj,
|
bpf_object__find_program_by_title(const struct bpf_object *obj,
|
||||||
const char *title);
|
const char *title);
|
||||||
|
LIBBPF_API struct bpf_program *
|
||||||
|
bpf_object__find_program_by_name(const struct bpf_object *obj,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
||||||
#define bpf_object__for_each_safe(pos, tmp) \
|
#define bpf_object__for_each_safe(pos, tmp) \
|
||||||
@@ -126,6 +172,8 @@ libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
|
|||||||
enum bpf_attach_type *expected_attach_type);
|
enum bpf_attach_type *expected_attach_type);
|
||||||
LIBBPF_API int libbpf_attach_type_by_name(const char *name,
|
LIBBPF_API int libbpf_attach_type_by_name(const char *name,
|
||||||
enum bpf_attach_type *attach_type);
|
enum bpf_attach_type *attach_type);
|
||||||
|
LIBBPF_API int libbpf_find_vmlinux_btf_id(const char *name,
|
||||||
|
enum bpf_attach_type attach_type);
|
||||||
|
|
||||||
/* Accessors of bpf_program */
|
/* Accessors of bpf_program */
|
||||||
struct bpf_program;
|
struct bpf_program;
|
||||||
@@ -149,9 +197,13 @@ LIBBPF_API void *bpf_program__priv(const struct bpf_program *prog);
|
|||||||
LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
|
LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
|
||||||
__u32 ifindex);
|
__u32 ifindex);
|
||||||
|
|
||||||
|
LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog);
|
||||||
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
|
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
|
||||||
bool needs_copy);
|
bool needs_copy);
|
||||||
|
|
||||||
|
/* returns program size in bytes */
|
||||||
|
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);
|
||||||
|
|
||||||
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
|
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
|
||||||
__u32 kern_version);
|
__u32 kern_version);
|
||||||
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
|
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
|
||||||
@@ -167,8 +219,11 @@ LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
|||||||
|
|
||||||
struct bpf_link;
|
struct bpf_link;
|
||||||
|
|
||||||
|
LIBBPF_API void bpf_link__disconnect(struct bpf_link *link);
|
||||||
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach(struct bpf_program *prog);
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
|
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
@@ -186,6 +241,10 @@ LIBBPF_API struct bpf_link *
|
|||||||
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||||
const char *tp_name);
|
const char *tp_name);
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_trace(struct bpf_program *prog);
|
||||||
|
struct bpf_map;
|
||||||
|
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);
|
||||||
struct bpf_insn;
|
struct bpf_insn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -261,8 +320,16 @@ LIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog);
|
|||||||
LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);
|
||||||
LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);
|
||||||
LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog);
|
||||||
|
LIBBPF_API int bpf_program__set_tracing(struct bpf_program *prog);
|
||||||
|
LIBBPF_API int bpf_program__set_struct_ops(struct bpf_program *prog);
|
||||||
|
LIBBPF_API int bpf_program__set_extension(struct bpf_program *prog);
|
||||||
|
|
||||||
|
LIBBPF_API enum bpf_prog_type bpf_program__get_type(struct bpf_program *prog);
|
||||||
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
|
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
|
||||||
enum bpf_prog_type type);
|
enum bpf_prog_type type);
|
||||||
|
|
||||||
|
LIBBPF_API enum bpf_attach_type
|
||||||
|
bpf_program__get_expected_attach_type(struct bpf_program *prog);
|
||||||
LIBBPF_API void
|
LIBBPF_API void
|
||||||
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||||
enum bpf_attach_type type);
|
enum bpf_attach_type type);
|
||||||
@@ -275,6 +342,9 @@ LIBBPF_API bool bpf_program__is_sched_cls(const struct bpf_program *prog);
|
|||||||
LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
|
||||||
LIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);
|
LIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);
|
||||||
|
LIBBPF_API bool bpf_program__is_tracing(const struct bpf_program *prog);
|
||||||
|
LIBBPF_API bool bpf_program__is_struct_ops(const struct bpf_program *prog);
|
||||||
|
LIBBPF_API bool bpf_program__is_extension(const struct bpf_program *prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No need for __attribute__((packed)), all members of 'bpf_map_def'
|
* No need for __attribute__((packed)), all members of 'bpf_map_def'
|
||||||
@@ -294,7 +364,6 @@ struct bpf_map_def {
|
|||||||
* The 'struct bpf_map' in include/linux/bpf.h is internal to the kernel,
|
* The 'struct bpf_map' in include/linux/bpf.h is internal to the kernel,
|
||||||
* so no need to worry about a name clash.
|
* so no need to worry about a name clash.
|
||||||
*/
|
*/
|
||||||
struct bpf_map;
|
|
||||||
LIBBPF_API struct bpf_map *
|
LIBBPF_API struct bpf_map *
|
||||||
bpf_object__find_map_by_name(const struct bpf_object *obj, const char *name);
|
bpf_object__find_map_by_name(const struct bpf_object *obj, const char *name);
|
||||||
|
|
||||||
@@ -334,6 +403,9 @@ LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
|
|||||||
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
||||||
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
||||||
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
||||||
|
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
||||||
|
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
||||||
|
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
@@ -355,8 +427,18 @@ LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|||||||
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
||||||
struct bpf_object **pobj, int *prog_fd);
|
struct bpf_object **pobj, int *prog_fd);
|
||||||
|
|
||||||
|
struct xdp_link_info {
|
||||||
|
__u32 prog_id;
|
||||||
|
__u32 drv_prog_id;
|
||||||
|
__u32 hw_prog_id;
|
||||||
|
__u32 skb_prog_id;
|
||||||
|
__u8 attach_mode;
|
||||||
|
};
|
||||||
|
|
||||||
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
|
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
|
||||||
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
||||||
|
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||||
|
size_t info_size, __u32 flags);
|
||||||
|
|
||||||
struct perf_buffer;
|
struct perf_buffer;
|
||||||
|
|
||||||
@@ -422,18 +504,6 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
|
|||||||
void **copy_mem, size_t *copy_size,
|
void **copy_mem, size_t *copy_size,
|
||||||
bpf_perf_event_print_t fn, void *private_data);
|
bpf_perf_event_print_t fn, void *private_data);
|
||||||
|
|
||||||
struct nlattr;
|
|
||||||
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
|
|
||||||
int libbpf_netlink_open(unsigned int *nl_pid);
|
|
||||||
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
|
||||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
|
|
||||||
int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex,
|
|
||||||
libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie);
|
|
||||||
int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
|
||||||
libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
|
|
||||||
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
|
||||||
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
|
||||||
|
|
||||||
struct bpf_prog_linfo;
|
struct bpf_prog_linfo;
|
||||||
struct bpf_prog_info;
|
struct bpf_prog_info;
|
||||||
|
|
||||||
@@ -460,6 +530,7 @@ LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
|
|||||||
LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
|
LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
|
||||||
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
|
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
|
||||||
enum bpf_prog_type prog_type, __u32 ifindex);
|
enum bpf_prog_type prog_type, __u32 ifindex);
|
||||||
|
LIBBPF_API bool bpf_probe_large_insn_limit(__u32 ifindex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get bpf_prog_info in continuous memory
|
* Get bpf_prog_info in continuous memory
|
||||||
@@ -540,6 +611,50 @@ bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
|
|||||||
*/
|
*/
|
||||||
LIBBPF_API int libbpf_num_possible_cpus(void);
|
LIBBPF_API int libbpf_num_possible_cpus(void);
|
||||||
|
|
||||||
|
struct bpf_map_skeleton {
|
||||||
|
const char *name;
|
||||||
|
struct bpf_map **map;
|
||||||
|
void **mmaped;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_prog_skeleton {
|
||||||
|
const char *name;
|
||||||
|
struct bpf_program **prog;
|
||||||
|
struct bpf_link **link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_object_skeleton {
|
||||||
|
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||||
|
|
||||||
|
const char *name;
|
||||||
|
void *data;
|
||||||
|
size_t data_sz;
|
||||||
|
|
||||||
|
struct bpf_object **obj;
|
||||||
|
|
||||||
|
int map_cnt;
|
||||||
|
int map_skel_sz; /* sizeof(struct bpf_skeleton_map) */
|
||||||
|
struct bpf_map_skeleton *maps;
|
||||||
|
|
||||||
|
int prog_cnt;
|
||||||
|
int prog_skel_sz; /* sizeof(struct bpf_skeleton_prog) */
|
||||||
|
struct bpf_prog_skeleton *progs;
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBBPF_API int
|
||||||
|
bpf_object__open_skeleton(struct bpf_object_skeleton *s,
|
||||||
|
const struct bpf_object_open_opts *opts);
|
||||||
|
LIBBPF_API int bpf_object__load_skeleton(struct bpf_object_skeleton *s);
|
||||||
|
LIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s);
|
||||||
|
LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);
|
||||||
|
LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);
|
||||||
|
|
||||||
|
enum libbpf_tristate {
|
||||||
|
TRI_NO = 0,
|
||||||
|
TRI_YES = 1,
|
||||||
|
TRI_MODULE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -183,4 +183,55 @@ LIBBPF_0.0.4 {
|
|||||||
perf_buffer__new;
|
perf_buffer__new;
|
||||||
perf_buffer__new_raw;
|
perf_buffer__new_raw;
|
||||||
perf_buffer__poll;
|
perf_buffer__poll;
|
||||||
|
xsk_umem__create;
|
||||||
} LIBBPF_0.0.3;
|
} LIBBPF_0.0.3;
|
||||||
|
|
||||||
|
LIBBPF_0.0.5 {
|
||||||
|
global:
|
||||||
|
bpf_btf_get_next_id;
|
||||||
|
} LIBBPF_0.0.4;
|
||||||
|
|
||||||
|
LIBBPF_0.0.6 {
|
||||||
|
global:
|
||||||
|
bpf_get_link_xdp_info;
|
||||||
|
bpf_map__get_pin_path;
|
||||||
|
bpf_map__is_pinned;
|
||||||
|
bpf_map__set_pin_path;
|
||||||
|
bpf_object__open_file;
|
||||||
|
bpf_object__open_mem;
|
||||||
|
bpf_program__attach_trace;
|
||||||
|
bpf_program__get_expected_attach_type;
|
||||||
|
bpf_program__get_type;
|
||||||
|
bpf_program__is_tracing;
|
||||||
|
bpf_program__set_tracing;
|
||||||
|
bpf_program__size;
|
||||||
|
btf__find_by_name_kind;
|
||||||
|
libbpf_find_vmlinux_btf_id;
|
||||||
|
} LIBBPF_0.0.5;
|
||||||
|
|
||||||
|
LIBBPF_0.0.7 {
|
||||||
|
global:
|
||||||
|
btf_dump__emit_type_decl;
|
||||||
|
bpf_link__disconnect;
|
||||||
|
bpf_map__attach_struct_ops;
|
||||||
|
bpf_map_delete_batch;
|
||||||
|
bpf_map_lookup_and_delete_batch;
|
||||||
|
bpf_map_lookup_batch;
|
||||||
|
bpf_map_update_batch;
|
||||||
|
bpf_object__find_program_by_name;
|
||||||
|
bpf_object__attach_skeleton;
|
||||||
|
bpf_object__destroy_skeleton;
|
||||||
|
bpf_object__detach_skeleton;
|
||||||
|
bpf_object__load_skeleton;
|
||||||
|
bpf_object__open_skeleton;
|
||||||
|
bpf_probe_large_insn_limit;
|
||||||
|
bpf_prog_attach_xattr;
|
||||||
|
bpf_program__attach;
|
||||||
|
bpf_program__name;
|
||||||
|
bpf_program__is_extension;
|
||||||
|
bpf_program__is_struct_ops;
|
||||||
|
bpf_program__set_extension;
|
||||||
|
bpf_program__set_struct_ops;
|
||||||
|
btf__align_of;
|
||||||
|
libbpf_find_kernel_btf;
|
||||||
|
} LIBBPF_0.0.6;
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ Name: libbpf
|
|||||||
Description: BPF library
|
Description: BPF library
|
||||||
Version: @VERSION@
|
Version: @VERSION@
|
||||||
Libs: -L${libdir} -lbpf
|
Libs: -L${libdir} -lbpf
|
||||||
Requires.private: libelf
|
Requires.private: libelf zlib
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|||||||
40
src/libbpf_common.h
Normal file
40
src/libbpf_common.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common user-facing libbpf helpers.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Facebook
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBBPF_LIBBPF_COMMON_H
|
||||||
|
#define __LIBBPF_LIBBPF_COMMON_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef LIBBPF_API
|
||||||
|
#define LIBBPF_API __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Helper macro to declare and initialize libbpf options struct
|
||||||
|
*
|
||||||
|
* This dance with uninitialized declaration, followed by memset to zero,
|
||||||
|
* followed by assignment using compound literal syntax is done to preserve
|
||||||
|
* ability to use a nice struct field initialization syntax and **hopefully**
|
||||||
|
* have all the padding bytes initialized to zero. It's not guaranteed though,
|
||||||
|
* when copying literal, that compiler won't copy garbage in literal's padding
|
||||||
|
* bytes, but that's the best way I've found and it seems to work in practice.
|
||||||
|
*
|
||||||
|
* Macro declares opts struct of given type and name, zero-initializes,
|
||||||
|
* including any extra padding, it with memset() and then assigns initial
|
||||||
|
* values provided by users in struct initializer-syntax as varargs.
|
||||||
|
*/
|
||||||
|
#define DECLARE_LIBBPF_OPTS(TYPE, NAME, ...) \
|
||||||
|
struct TYPE NAME = ({ \
|
||||||
|
memset(&NAME, 0, sizeof(struct TYPE)); \
|
||||||
|
(struct TYPE) { \
|
||||||
|
.sz = sizeof(struct TYPE), \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
}; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* __LIBBPF_LIBBPF_COMMON_H */
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
|
#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
|
||||||
#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
|
#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
|
||||||
#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
|
#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
|
||||||
|
|||||||
@@ -29,6 +29,26 @@
|
|||||||
#ifndef max
|
#ifndef max
|
||||||
# define max(x, y) ((x) < (y) ? (y) : (x))
|
# define max(x, y) ((x) < (y) ? (y) : (x))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef offsetofend
|
||||||
|
# define offsetofend(TYPE, FIELD) \
|
||||||
|
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Symbol versioning is different between static and shared library.
|
||||||
|
* Properly versioned symbols are needed for shared library, but
|
||||||
|
* only the symbol of the new version is needed for static library.
|
||||||
|
*/
|
||||||
|
#ifdef SHARED
|
||||||
|
# define COMPAT_VERSION(internal_name, api_name, version) \
|
||||||
|
asm(".symver " #internal_name "," #api_name "@" #version);
|
||||||
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||||
|
asm(".symver " #internal_name "," #api_name "@@" #version);
|
||||||
|
#else
|
||||||
|
# define COMPAT_VERSION(internal_name, api_name, version)
|
||||||
|
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||||
|
extern typeof(internal_name) api_name \
|
||||||
|
__attribute__((alias(#internal_name)));
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void libbpf_print(enum libbpf_print_level level,
|
extern void libbpf_print(enum libbpf_print_level level,
|
||||||
const char *format, ...)
|
const char *format, ...)
|
||||||
@@ -39,11 +59,178 @@ do { \
|
|||||||
libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \
|
libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define pr_warning(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__)
|
#define pr_warn(fmt, ...) __pr(LIBBPF_WARN, fmt, ##__VA_ARGS__)
|
||||||
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
||||||
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
static inline bool libbpf_validate_opts(const char *opts,
|
||||||
|
size_t opts_sz, size_t user_sz,
|
||||||
|
const char *type_name)
|
||||||
|
{
|
||||||
|
if (user_sz < sizeof(size_t)) {
|
||||||
|
pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (user_sz > opts_sz) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = opts_sz; i < user_sz; i++) {
|
||||||
|
if (opts[i]) {
|
||||||
|
pr_warn("%s has non-zero extra bytes\n",
|
||||||
|
type_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPTS_VALID(opts, type) \
|
||||||
|
(!(opts) || libbpf_validate_opts((const char *)opts, \
|
||||||
|
offsetofend(struct type, \
|
||||||
|
type##__last_field), \
|
||||||
|
(opts)->sz, #type))
|
||||||
|
#define OPTS_HAS(opts, field) \
|
||||||
|
((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
|
||||||
|
#define OPTS_GET(opts, field, fallback_value) \
|
||||||
|
(OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
|
||||||
|
|
||||||
|
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
||||||
|
int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||||
const char *str_sec, size_t str_len);
|
const char *str_sec, size_t str_len);
|
||||||
|
|
||||||
|
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
||||||
|
__u32 *size);
|
||||||
|
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
||||||
|
__u32 *off);
|
||||||
|
|
||||||
|
struct nlattr;
|
||||||
|
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
|
||||||
|
int libbpf_netlink_open(unsigned int *nl_pid);
|
||||||
|
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
||||||
|
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
|
||||||
|
int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex,
|
||||||
|
libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie);
|
||||||
|
int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
||||||
|
libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
|
||||||
|
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
||||||
|
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
||||||
|
|
||||||
|
struct btf_ext_info {
|
||||||
|
/*
|
||||||
|
* info points to the individual info section (e.g. func_info and
|
||||||
|
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
||||||
|
*/
|
||||||
|
void *info;
|
||||||
|
__u32 rec_size;
|
||||||
|
__u32 len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define for_each_btf_ext_sec(seg, sec) \
|
||||||
|
for (sec = (seg)->info; \
|
||||||
|
(void *)sec < (seg)->info + (seg)->len; \
|
||||||
|
sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
|
||||||
|
(seg)->rec_size * sec->num_info)
|
||||||
|
|
||||||
|
#define for_each_btf_ext_rec(seg, sec, i, rec) \
|
||||||
|
for (i = 0, rec = (void *)&(sec)->data; \
|
||||||
|
i < (sec)->num_info; \
|
||||||
|
i++, rec = (void *)rec + (seg)->rec_size)
|
||||||
|
|
||||||
|
struct btf_ext {
|
||||||
|
union {
|
||||||
|
struct btf_ext_header *hdr;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
struct btf_ext_info func_info;
|
||||||
|
struct btf_ext_info line_info;
|
||||||
|
struct btf_ext_info field_reloc_info;
|
||||||
|
__u32 data_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct btf_ext_info_sec {
|
||||||
|
__u32 sec_name_off;
|
||||||
|
__u32 num_info;
|
||||||
|
/* Followed by num_info * record_size number of bytes */
|
||||||
|
__u8 data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_func_info checked by the loader */
|
||||||
|
struct bpf_func_info_min {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_line_info checked by the loader */
|
||||||
|
struct bpf_line_info_min {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 file_name_off;
|
||||||
|
__u32 line_off;
|
||||||
|
__u32 line_col;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* bpf_field_info_kind encodes which aspect of captured field has to be
|
||||||
|
* adjusted by relocations. Currently supported values are:
|
||||||
|
* - BPF_FIELD_BYTE_OFFSET: field offset (in bytes);
|
||||||
|
* - BPF_FIELD_EXISTS: field existence (1, if field exists; 0, otherwise);
|
||||||
|
*/
|
||||||
|
enum bpf_field_info_kind {
|
||||||
|
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
||||||
|
BPF_FIELD_BYTE_SIZE = 1,
|
||||||
|
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
||||||
|
BPF_FIELD_SIGNED = 3,
|
||||||
|
BPF_FIELD_LSHIFT_U64 = 4,
|
||||||
|
BPF_FIELD_RSHIFT_U64 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_field_reloc checked by the loader
|
||||||
|
*
|
||||||
|
* Field relocation captures the following data:
|
||||||
|
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
||||||
|
* its insn->imm field to be relocated with actual field info;
|
||||||
|
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
||||||
|
* field;
|
||||||
|
* - access_str_off - offset into corresponding .BTF string section. String
|
||||||
|
* itself encodes an accessed field using a sequence of field and array
|
||||||
|
* indicies, separated by colon (:). It's conceptually very close to LLVM's
|
||||||
|
* getelementptr ([0]) instruction's arguments for identifying offset to
|
||||||
|
* a field.
|
||||||
|
*
|
||||||
|
* Example to provide a better feel.
|
||||||
|
*
|
||||||
|
* struct sample {
|
||||||
|
* int a;
|
||||||
|
* struct {
|
||||||
|
* int b[10];
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct sample *s = ...;
|
||||||
|
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||||
|
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||||
|
* // b is field #0 inside anon struct, accessing elem #5)
|
||||||
|
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||||
|
*
|
||||||
|
* type_id for all relocs in this example will capture BTF type id of
|
||||||
|
* `struct sample`.
|
||||||
|
*
|
||||||
|
* Such relocation is emitted when using __builtin_preserve_access_index()
|
||||||
|
* Clang built-in, passing expression that captures field address, e.g.:
|
||||||
|
*
|
||||||
|
* bpf_probe_read(&dst, sizeof(dst),
|
||||||
|
* __builtin_preserve_access_index(&src->a.b.c));
|
||||||
|
*
|
||||||
|
* In this case Clang will emit field relocation recording necessary data to
|
||||||
|
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
||||||
|
*
|
||||||
|
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
||||||
|
*/
|
||||||
|
struct bpf_field_reloc {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
__u32 access_str_off;
|
||||||
|
enum bpf_field_info_kind kind;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
static bool grep(const char *buffer, const char *pattern)
|
static bool grep(const char *buffer, const char *pattern)
|
||||||
{
|
{
|
||||||
return !!strstr(buffer, pattern);
|
return !!strstr(buffer, pattern);
|
||||||
@@ -102,6 +105,9 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
|||||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||||
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||||
|
case BPF_PROG_TYPE_TRACING:
|
||||||
|
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||||
|
case BPF_PROG_TYPE_EXT:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -244,11 +250,13 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
|||||||
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||||
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||||
case BPF_MAP_TYPE_DEVMAP:
|
case BPF_MAP_TYPE_DEVMAP:
|
||||||
|
case BPF_MAP_TYPE_DEVMAP_HASH:
|
||||||
case BPF_MAP_TYPE_SOCKMAP:
|
case BPF_MAP_TYPE_SOCKMAP:
|
||||||
case BPF_MAP_TYPE_CPUMAP:
|
case BPF_MAP_TYPE_CPUMAP:
|
||||||
case BPF_MAP_TYPE_XSKMAP:
|
case BPF_MAP_TYPE_XSKMAP:
|
||||||
case BPF_MAP_TYPE_SOCKHASH:
|
case BPF_MAP_TYPE_SOCKHASH:
|
||||||
case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
|
case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
|
||||||
|
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -319,3 +327,24 @@ bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe for availability of kernel commit (5.3):
|
||||||
|
*
|
||||||
|
* c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
|
||||||
|
*/
|
||||||
|
bool bpf_probe_large_insn_limit(__u32 ifindex)
|
||||||
|
{
|
||||||
|
struct bpf_insn insns[BPF_MAXINSNS + 1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BPF_MAXINSNS; i++)
|
||||||
|
insns[i] = BPF_MOV64_IMM(BPF_REG_0, 1);
|
||||||
|
insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
probe_load(BPF_PROG_TYPE_SCHED_CLS, insns, ARRAY_SIZE(insns), NULL, 0,
|
||||||
|
ifindex);
|
||||||
|
|
||||||
|
return errno != E2BIG && errno != EINVAL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,8 +12,12 @@
|
|||||||
|
|
||||||
#include "bpf.h"
|
#include "bpf.h"
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
|
#include "libbpf_internal.h"
|
||||||
#include "nlattr.h"
|
#include "nlattr.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
#ifndef SOL_NETLINK
|
#ifndef SOL_NETLINK
|
||||||
#define SOL_NETLINK 270
|
#define SOL_NETLINK 270
|
||||||
#endif
|
#endif
|
||||||
@@ -24,7 +28,7 @@ typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
|
|||||||
struct xdp_id_md {
|
struct xdp_id_md {
|
||||||
int ifindex;
|
int ifindex;
|
||||||
__u32 flags;
|
__u32 flags;
|
||||||
__u32 id;
|
struct xdp_link_info info;
|
||||||
};
|
};
|
||||||
|
|
||||||
int libbpf_netlink_open(__u32 *nl_pid)
|
int libbpf_netlink_open(__u32 *nl_pid)
|
||||||
@@ -43,7 +47,7 @@ int libbpf_netlink_open(__u32 *nl_pid)
|
|||||||
|
|
||||||
if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
|
if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
|
||||||
&one, sizeof(one)) < 0) {
|
&one, sizeof(one)) < 0) {
|
||||||
fprintf(stderr, "Netlink error reporting not supported\n");
|
pr_warn("Netlink error reporting not supported\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
@@ -202,26 +206,11 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
|||||||
return dump_link_nlmsg(cookie, ifi, tb);
|
return dump_link_nlmsg(cookie, ifi, tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char get_xdp_id_attr(unsigned char mode, __u32 flags)
|
static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
|
||||||
{
|
|
||||||
if (mode != XDP_ATTACHED_MULTI)
|
|
||||||
return IFLA_XDP_PROG_ID;
|
|
||||||
if (flags & XDP_FLAGS_DRV_MODE)
|
|
||||||
return IFLA_XDP_DRV_PROG_ID;
|
|
||||||
if (flags & XDP_FLAGS_HW_MODE)
|
|
||||||
return IFLA_XDP_HW_PROG_ID;
|
|
||||||
if (flags & XDP_FLAGS_SKB_MODE)
|
|
||||||
return IFLA_XDP_SKB_PROG_ID;
|
|
||||||
|
|
||||||
return IFLA_XDP_UNSPEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_xdp_id(void *cookie, void *msg, struct nlattr **tb)
|
|
||||||
{
|
{
|
||||||
struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
|
struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
|
||||||
struct xdp_id_md *xdp_id = cookie;
|
struct xdp_id_md *xdp_id = cookie;
|
||||||
struct ifinfomsg *ifinfo = msg;
|
struct ifinfomsg *ifinfo = msg;
|
||||||
unsigned char mode, xdp_attr;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
|
if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
|
||||||
@@ -237,27 +226,40 @@ static int get_xdp_id(void *cookie, void *msg, struct nlattr **tb)
|
|||||||
if (!xdp_tb[IFLA_XDP_ATTACHED])
|
if (!xdp_tb[IFLA_XDP_ATTACHED])
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mode = libbpf_nla_getattr_u8(xdp_tb[IFLA_XDP_ATTACHED]);
|
xdp_id->info.attach_mode = libbpf_nla_getattr_u8(
|
||||||
if (mode == XDP_ATTACHED_NONE)
|
xdp_tb[IFLA_XDP_ATTACHED]);
|
||||||
|
|
||||||
|
if (xdp_id->info.attach_mode == XDP_ATTACHED_NONE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
xdp_attr = get_xdp_id_attr(mode, xdp_id->flags);
|
if (xdp_tb[IFLA_XDP_PROG_ID])
|
||||||
if (!xdp_attr || !xdp_tb[xdp_attr])
|
xdp_id->info.prog_id = libbpf_nla_getattr_u32(
|
||||||
return 0;
|
xdp_tb[IFLA_XDP_PROG_ID]);
|
||||||
|
|
||||||
xdp_id->id = libbpf_nla_getattr_u32(xdp_tb[xdp_attr]);
|
if (xdp_tb[IFLA_XDP_SKB_PROG_ID])
|
||||||
|
xdp_id->info.skb_prog_id = libbpf_nla_getattr_u32(
|
||||||
|
xdp_tb[IFLA_XDP_SKB_PROG_ID]);
|
||||||
|
|
||||||
|
if (xdp_tb[IFLA_XDP_DRV_PROG_ID])
|
||||||
|
xdp_id->info.drv_prog_id = libbpf_nla_getattr_u32(
|
||||||
|
xdp_tb[IFLA_XDP_DRV_PROG_ID]);
|
||||||
|
|
||||||
|
if (xdp_tb[IFLA_XDP_HW_PROG_ID])
|
||||||
|
xdp_id->info.hw_prog_id = libbpf_nla_getattr_u32(
|
||||||
|
xdp_tb[IFLA_XDP_HW_PROG_ID]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
|
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||||
|
size_t info_size, __u32 flags)
|
||||||
{
|
{
|
||||||
struct xdp_id_md xdp_id = {};
|
struct xdp_id_md xdp_id = {};
|
||||||
int sock, ret;
|
int sock, ret;
|
||||||
__u32 nl_pid;
|
__u32 nl_pid;
|
||||||
__u32 mask;
|
__u32 mask;
|
||||||
|
|
||||||
if (flags & ~XDP_FLAGS_MASK)
|
if (flags & ~XDP_FLAGS_MASK || !info_size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Check whether the single {HW,DRV,SKB} mode is set */
|
/* Check whether the single {HW,DRV,SKB} mode is set */
|
||||||
@@ -273,14 +275,44 @@ int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
|
|||||||
xdp_id.ifindex = ifindex;
|
xdp_id.ifindex = ifindex;
|
||||||
xdp_id.flags = flags;
|
xdp_id.flags = flags;
|
||||||
|
|
||||||
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
|
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
*prog_id = xdp_id.id;
|
size_t sz = min(info_size, sizeof(xdp_id.info));
|
||||||
|
|
||||||
|
memcpy(info, &xdp_id.info, sz);
|
||||||
|
memset((void *) info + sz, 0, info_size - sz);
|
||||||
|
}
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
|
||||||
|
{
|
||||||
|
if (info->attach_mode != XDP_ATTACHED_MULTI)
|
||||||
|
return info->prog_id;
|
||||||
|
if (flags & XDP_FLAGS_DRV_MODE)
|
||||||
|
return info->drv_prog_id;
|
||||||
|
if (flags & XDP_FLAGS_HW_MODE)
|
||||||
|
return info->hw_prog_id;
|
||||||
|
if (flags & XDP_FLAGS_SKB_MODE)
|
||||||
|
return info->skb_prog_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
|
||||||
|
{
|
||||||
|
struct xdp_link_info info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = bpf_get_link_xdp_info(ifindex, &info, sizeof(info), flags);
|
||||||
|
if (!ret)
|
||||||
|
*prog_id = get_xdp_id(&info, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
||||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
|
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
13
src/nlattr.c
13
src/nlattr.c
@@ -8,10 +8,14 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "nlattr.h"
|
#include "nlattr.h"
|
||||||
|
#include "libbpf_internal.h"
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
|
static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
|
||||||
[LIBBPF_NLA_U8] = sizeof(uint8_t),
|
[LIBBPF_NLA_U8] = sizeof(uint8_t),
|
||||||
[LIBBPF_NLA_U16] = sizeof(uint16_t),
|
[LIBBPF_NLA_U16] = sizeof(uint16_t),
|
||||||
@@ -121,8 +125,8 @@ int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tb[type])
|
if (tb[type])
|
||||||
fprintf(stderr, "Attribute of type %#x found multiple times in message, "
|
pr_warn("Attribute of type %#x found multiple times in message, "
|
||||||
"previous attribute is being ignored.\n", type);
|
"previous attribute is being ignored.\n", type);
|
||||||
|
|
||||||
tb[type] = nla;
|
tb[type] = nla;
|
||||||
}
|
}
|
||||||
@@ -181,15 +185,14 @@ int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
|
|||||||
|
|
||||||
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) {
|
||||||
fprintf(stderr,
|
pr_warn("Failed to parse extended error attributes\n");
|
||||||
"Failed to parse extended error attributes\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tb[NLMSGERR_ATTR_MSG])
|
if (tb[NLMSGERR_ATTR_MSG])
|
||||||
errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
|
errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
|
||||||
|
|
||||||
fprintf(stderr, "Kernel error message: %s\n", errmsg);
|
pr_warn("Kernel error message: %s\n", errmsg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "str_error.h"
|
#include "str_error.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper to allow for building in non-GNU systems such as Alpine Linux's musl
|
* Wrapper to allow for building in non-GNU systems such as Alpine Linux's musl
|
||||||
* libc, while checking strerror_r() return to avoid having to check this in
|
* libc, while checking strerror_r() return to avoid having to check this in
|
||||||
|
|||||||
282
src/xsk.c
282
src/xsk.c
@@ -32,6 +32,9 @@
|
|||||||
#include "libbpf_internal.h"
|
#include "libbpf_internal.h"
|
||||||
#include "xsk.h"
|
#include "xsk.h"
|
||||||
|
|
||||||
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
|
|
||||||
#ifndef SOL_XDP
|
#ifndef SOL_XDP
|
||||||
#define SOL_XDP 283
|
#define SOL_XDP 283
|
||||||
#endif
|
#endif
|
||||||
@@ -65,7 +68,6 @@ struct xsk_socket {
|
|||||||
int xsks_map_fd;
|
int xsks_map_fd;
|
||||||
__u32 queue_id;
|
__u32 queue_id;
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
bool zc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xsk_nl_info {
|
struct xsk_nl_info {
|
||||||
@@ -74,22 +76,20 @@ struct xsk_nl_info {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For 32-bit systems, we need to use mmap2 as the offsets are 64-bit.
|
/* Up until and including Linux 5.3 */
|
||||||
* Unfortunately, it is not part of glibc.
|
struct xdp_ring_offset_v1 {
|
||||||
*/
|
__u64 producer;
|
||||||
static inline void *xsk_mmap(void *addr, size_t length, int prot, int flags,
|
__u64 consumer;
|
||||||
int fd, __u64 offset)
|
__u64 desc;
|
||||||
{
|
};
|
||||||
#ifdef __NR_mmap2
|
|
||||||
unsigned int page_shift = __builtin_ffs(getpagesize()) - 1;
|
|
||||||
long ret = syscall(__NR_mmap2, addr, length, prot, flags, fd,
|
|
||||||
(off_t)(offset >> page_shift));
|
|
||||||
|
|
||||||
return (void *)ret;
|
/* Up until and including Linux 5.3 */
|
||||||
#else
|
struct xdp_mmap_offsets_v1 {
|
||||||
return mmap(addr, length, prot, flags, fd, offset);
|
struct xdp_ring_offset_v1 rx;
|
||||||
#endif
|
struct xdp_ring_offset_v1 tx;
|
||||||
}
|
struct xdp_ring_offset_v1 fr;
|
||||||
|
struct xdp_ring_offset_v1 cr;
|
||||||
|
};
|
||||||
|
|
||||||
int xsk_umem__fd(const struct xsk_umem *umem)
|
int xsk_umem__fd(const struct xsk_umem *umem)
|
||||||
{
|
{
|
||||||
@@ -116,6 +116,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
|||||||
cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
||||||
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
||||||
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
||||||
|
cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
|||||||
cfg->comp_size = usr_cfg->comp_size;
|
cfg->comp_size = usr_cfg->comp_size;
|
||||||
cfg->frame_size = usr_cfg->frame_size;
|
cfg->frame_size = usr_cfg->frame_size;
|
||||||
cfg->frame_headroom = usr_cfg->frame_headroom;
|
cfg->frame_headroom = usr_cfg->frame_headroom;
|
||||||
|
cfg->flags = usr_cfg->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
||||||
@@ -149,14 +151,66 @@ static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
static void xsk_mmap_offsets_v1(struct xdp_mmap_offsets *off)
|
||||||
struct xsk_ring_prod *fill, struct xsk_ring_cons *comp,
|
{
|
||||||
const struct xsk_umem_config *usr_config)
|
struct xdp_mmap_offsets_v1 off_v1;
|
||||||
|
|
||||||
|
/* getsockopt on a kernel <= 5.3 has no flags fields.
|
||||||
|
* Copy over the offsets to the correct places in the >=5.4 format
|
||||||
|
* and put the flags where they would have been on that kernel.
|
||||||
|
*/
|
||||||
|
memcpy(&off_v1, off, sizeof(off_v1));
|
||||||
|
|
||||||
|
off->rx.producer = off_v1.rx.producer;
|
||||||
|
off->rx.consumer = off_v1.rx.consumer;
|
||||||
|
off->rx.desc = off_v1.rx.desc;
|
||||||
|
off->rx.flags = off_v1.rx.consumer + sizeof(__u32);
|
||||||
|
|
||||||
|
off->tx.producer = off_v1.tx.producer;
|
||||||
|
off->tx.consumer = off_v1.tx.consumer;
|
||||||
|
off->tx.desc = off_v1.tx.desc;
|
||||||
|
off->tx.flags = off_v1.tx.consumer + sizeof(__u32);
|
||||||
|
|
||||||
|
off->fr.producer = off_v1.fr.producer;
|
||||||
|
off->fr.consumer = off_v1.fr.consumer;
|
||||||
|
off->fr.desc = off_v1.fr.desc;
|
||||||
|
off->fr.flags = off_v1.fr.consumer + sizeof(__u32);
|
||||||
|
|
||||||
|
off->cr.producer = off_v1.cr.producer;
|
||||||
|
off->cr.consumer = off_v1.cr.consumer;
|
||||||
|
off->cr.desc = off_v1.cr.desc;
|
||||||
|
off->cr.flags = off_v1.cr.consumer + sizeof(__u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xsk_get_mmap_offsets(int fd, struct xdp_mmap_offsets *off)
|
||||||
|
{
|
||||||
|
socklen_t optlen;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
optlen = sizeof(*off);
|
||||||
|
err = getsockopt(fd, SOL_XDP, XDP_MMAP_OFFSETS, off, &optlen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (optlen == sizeof(*off))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (optlen == sizeof(struct xdp_mmap_offsets_v1)) {
|
||||||
|
xsk_mmap_offsets_v1(off);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||||
|
__u64 size, struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *usr_config)
|
||||||
{
|
{
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
struct xdp_umem_reg mr;
|
struct xdp_umem_reg mr;
|
||||||
struct xsk_umem *umem;
|
struct xsk_umem *umem;
|
||||||
socklen_t optlen;
|
|
||||||
void *map;
|
void *map;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -178,10 +232,12 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
umem->umem_area = umem_area;
|
umem->umem_area = umem_area;
|
||||||
xsk_set_umem_config(&umem->config, usr_config);
|
xsk_set_umem_config(&umem->config, usr_config);
|
||||||
|
|
||||||
|
memset(&mr, 0, sizeof(mr));
|
||||||
mr.addr = (uintptr_t)umem_area;
|
mr.addr = (uintptr_t)umem_area;
|
||||||
mr.len = size;
|
mr.len = size;
|
||||||
mr.chunk_size = umem->config.frame_size;
|
mr.chunk_size = umem->config.frame_size;
|
||||||
mr.headroom = umem->config.frame_headroom;
|
mr.headroom = umem->config.frame_headroom;
|
||||||
|
mr.flags = umem->config.flags;
|
||||||
|
|
||||||
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
|
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -203,17 +259,15 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
optlen = sizeof(off);
|
err = xsk_get_mmap_offsets(umem->fd, &off);
|
||||||
err = getsockopt(umem->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = xsk_mmap(NULL, off.fr.desc +
|
map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64),
|
||||||
umem->config.fill_size * sizeof(__u64),
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
XDP_UMEM_PGOFF_FILL_RING);
|
||||||
umem->fd, XDP_UMEM_PGOFF_FILL_RING);
|
|
||||||
if (map == MAP_FAILED) {
|
if (map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
@@ -224,13 +278,13 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
fill->size = umem->config.fill_size;
|
fill->size = umem->config.fill_size;
|
||||||
fill->producer = map + off.fr.producer;
|
fill->producer = map + off.fr.producer;
|
||||||
fill->consumer = map + off.fr.consumer;
|
fill->consumer = map + off.fr.consumer;
|
||||||
|
fill->flags = map + off.fr.flags;
|
||||||
fill->ring = map + off.fr.desc;
|
fill->ring = map + off.fr.desc;
|
||||||
fill->cached_cons = umem->config.fill_size;
|
fill->cached_cons = umem->config.fill_size;
|
||||||
|
|
||||||
map = xsk_mmap(NULL,
|
map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
||||||
off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
XDP_UMEM_PGOFF_COMPLETION_RING);
|
||||||
umem->fd, XDP_UMEM_PGOFF_COMPLETION_RING);
|
|
||||||
if (map == MAP_FAILED) {
|
if (map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_mmap;
|
goto out_mmap;
|
||||||
@@ -241,6 +295,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
|||||||
comp->size = umem->config.comp_size;
|
comp->size = umem->config.comp_size;
|
||||||
comp->producer = map + off.cr.producer;
|
comp->producer = map + off.cr.producer;
|
||||||
comp->consumer = map + off.cr.consumer;
|
comp->consumer = map + off.cr.consumer;
|
||||||
|
comp->flags = map + off.cr.flags;
|
||||||
comp->ring = map + off.cr.desc;
|
comp->ring = map + off.cr.desc;
|
||||||
|
|
||||||
*umem_ptr = umem;
|
*umem_ptr = umem;
|
||||||
@@ -255,6 +310,29 @@ out_umem_alloc:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct xsk_umem_config_v1 {
|
||||||
|
__u32 fill_size;
|
||||||
|
__u32 comp_size;
|
||||||
|
__u32 frame_size;
|
||||||
|
__u32 frame_headroom;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
|
||||||
|
__u64 size, struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *usr_config)
|
||||||
|
{
|
||||||
|
struct xsk_umem_config config;
|
||||||
|
|
||||||
|
memcpy(&config, usr_config, sizeof(struct xsk_umem_config_v1));
|
||||||
|
config.flags = 0;
|
||||||
|
|
||||||
|
return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp,
|
||||||
|
&config);
|
||||||
|
}
|
||||||
|
COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
|
||||||
|
DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
|
||||||
|
|
||||||
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
static const int log_buf_size = 16 * 1024;
|
static const int log_buf_size = 16 * 1024;
|
||||||
@@ -264,33 +342,55 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
/* This is the C-program:
|
/* This is the C-program:
|
||||||
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
||||||
* {
|
* {
|
||||||
* int index = ctx->rx_queue_index;
|
* int ret, index = ctx->rx_queue_index;
|
||||||
*
|
*
|
||||||
* // A set entry here means that the correspnding queue_id
|
* // A set entry here means that the correspnding queue_id
|
||||||
* // has an active AF_XDP socket bound to it.
|
* // has an active AF_XDP socket bound to it.
|
||||||
|
* ret = bpf_redirect_map(&xsks_map, index, XDP_PASS);
|
||||||
|
* if (ret > 0)
|
||||||
|
* return ret;
|
||||||
|
*
|
||||||
|
* // Fallback for pre-5.3 kernels, not supporting default
|
||||||
|
* // action in the flags parameter.
|
||||||
* if (bpf_map_lookup_elem(&xsks_map, &index))
|
* if (bpf_map_lookup_elem(&xsks_map, &index))
|
||||||
* return bpf_redirect_map(&xsks_map, index, 0);
|
* return bpf_redirect_map(&xsks_map, index, 0);
|
||||||
*
|
|
||||||
* return XDP_PASS;
|
* return XDP_PASS;
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
struct bpf_insn prog[] = {
|
struct bpf_insn prog[] = {
|
||||||
/* r1 = *(u32 *)(r1 + 16) */
|
/* r2 = *(u32 *)(r1 + 16) */
|
||||||
BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, 16),
|
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 16),
|
||||||
/* *(u32 *)(r10 - 4) = r1 */
|
/* *(u32 *)(r10 - 4) = r2 */
|
||||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, -4),
|
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -4),
|
||||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
/* r1 = xskmap[] */
|
||||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
|
||||||
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
||||||
|
/* r3 = XDP_PASS */
|
||||||
|
BPF_MOV64_IMM(BPF_REG_3, 2),
|
||||||
|
/* call bpf_redirect_map */
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
||||||
|
/* if w0 != 0 goto pc+13 */
|
||||||
|
BPF_JMP32_IMM(BPF_JSGT, BPF_REG_0, 0, 13),
|
||||||
|
/* r2 = r10 */
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
/* r2 += -4 */
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
||||||
|
/* r1 = xskmap[] */
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
||||||
|
/* call bpf_map_lookup_elem */
|
||||||
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||||
|
/* r1 = r0 */
|
||||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||||
BPF_MOV32_IMM(BPF_REG_0, 2),
|
/* r0 = XDP_PASS */
|
||||||
/* if r1 == 0 goto +5 */
|
BPF_MOV64_IMM(BPF_REG_0, 2),
|
||||||
|
/* if r1 == 0 goto pc+5 */
|
||||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
|
||||||
/* r2 = *(u32 *)(r10 - 4) */
|
/* r2 = *(u32 *)(r10 - 4) */
|
||||||
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
|
||||||
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, -4),
|
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, -4),
|
||||||
BPF_MOV32_IMM(BPF_REG_3, 0),
|
/* r1 = xskmap[] */
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
|
||||||
|
/* r3 = 0 */
|
||||||
|
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||||
|
/* call bpf_redirect_map */
|
||||||
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
||||||
/* The jumps are to this instruction */
|
/* The jumps are to this instruction */
|
||||||
BPF_EXIT_INSN(),
|
BPF_EXIT_INSN(),
|
||||||
@@ -301,7 +401,7 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
"LGPL-2.1 or BSD-2-Clause", 0, log_buf,
|
"LGPL-2.1 or BSD-2-Clause", 0, log_buf,
|
||||||
log_buf_size);
|
log_buf_size);
|
||||||
if (prog_fd < 0) {
|
if (prog_fd < 0) {
|
||||||
pr_warning("BPF log buffer:\n%s", log_buf);
|
pr_warn("BPF log buffer:\n%s", log_buf);
|
||||||
return prog_fd;
|
return prog_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,17 +417,16 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
|
|
||||||
static int xsk_get_max_queues(struct xsk_socket *xsk)
|
static int xsk_get_max_queues(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
struct ethtool_channels channels;
|
struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
|
||||||
struct ifreq ifr;
|
struct ifreq ifr = {};
|
||||||
int fd, err, ret;
|
int fd, err, ret;
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
channels.cmd = ETHTOOL_GCHANNELS;
|
|
||||||
ifr.ifr_data = (void *)&channels;
|
ifr.ifr_data = (void *)&channels;
|
||||||
strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
|
memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
|
||||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||||
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
||||||
if (err && errno != EOPNOTSUPP) {
|
if (err && errno != EOPNOTSUPP) {
|
||||||
@@ -335,13 +434,18 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channels.max_combined == 0 || errno == EOPNOTSUPP)
|
if (err) {
|
||||||
/* If the device says it has no channels, then all traffic
|
/* If the device says it has no channels, then all traffic
|
||||||
* is sent to a single stream, so max queues = 1.
|
* is sent to a single stream, so max queues = 1.
|
||||||
*/
|
*/
|
||||||
ret = 1;
|
ret = 1;
|
||||||
else
|
} else {
|
||||||
ret = channels.max_combined;
|
/* Take the max of rx, tx, combined. Drivers return
|
||||||
|
* the number of channels in different ways.
|
||||||
|
*/
|
||||||
|
ret = max(channels.max_rx, channels.max_tx);
|
||||||
|
ret = max(ret, (int)channels.max_combined);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -457,6 +561,8 @@ static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
||||||
|
if (xsk->prog_fd < 0)
|
||||||
|
return -errno;
|
||||||
err = xsk_lookup_bpf_maps(xsk);
|
err = xsk_lookup_bpf_maps(xsk);
|
||||||
if (err) {
|
if (err) {
|
||||||
close(xsk->prog_fd);
|
close(xsk->prog_fd);
|
||||||
@@ -464,7 +570,8 @@ static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xsk_set_bpf_maps(xsk);
|
if (xsk->rx)
|
||||||
|
err = xsk_set_bpf_maps(xsk);
|
||||||
if (err) {
|
if (err) {
|
||||||
xsk_delete_bpf_maps(xsk);
|
xsk_delete_bpf_maps(xsk);
|
||||||
close(xsk->prog_fd);
|
close(xsk->prog_fd);
|
||||||
@@ -482,23 +589,27 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
void *rx_map = NULL, *tx_map = NULL;
|
void *rx_map = NULL, *tx_map = NULL;
|
||||||
struct sockaddr_xdp sxdp = {};
|
struct sockaddr_xdp sxdp = {};
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
struct xdp_options opts;
|
|
||||||
struct xsk_socket *xsk;
|
struct xsk_socket *xsk;
|
||||||
socklen_t optlen;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!umem || !xsk_ptr || !rx || !tx)
|
if (!umem || !xsk_ptr || !(rx || tx))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (umem->refcount) {
|
|
||||||
pr_warning("Error: shared umems not supported by libbpf.\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
xsk = calloc(1, sizeof(*xsk));
|
xsk = calloc(1, sizeof(*xsk));
|
||||||
if (!xsk)
|
if (!xsk)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
|
||||||
|
if (err)
|
||||||
|
goto out_xsk_alloc;
|
||||||
|
|
||||||
|
if (umem->refcount &&
|
||||||
|
!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
||||||
|
pr_warn("Error: shared umems not supported by libbpf supplied XDP program.\n");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out_xsk_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
if (umem->refcount++ > 0) {
|
if (umem->refcount++ > 0) {
|
||||||
xsk->fd = socket(AF_XDP, SOCK_RAW, 0);
|
xsk->fd = socket(AF_XDP, SOCK_RAW, 0);
|
||||||
if (xsk->fd < 0) {
|
if (xsk->fd < 0) {
|
||||||
@@ -517,13 +628,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
strncpy(xsk->ifname, ifname, IFNAMSIZ - 1);
|
memcpy(xsk->ifname, ifname, IFNAMSIZ - 1);
|
||||||
xsk->ifname[IFNAMSIZ - 1] = '\0';
|
xsk->ifname[IFNAMSIZ - 1] = '\0';
|
||||||
|
|
||||||
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
|
|
||||||
if (err)
|
|
||||||
goto out_socket;
|
|
||||||
|
|
||||||
if (rx) {
|
if (rx) {
|
||||||
err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
|
err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
|
||||||
&xsk->config.rx_size,
|
&xsk->config.rx_size,
|
||||||
@@ -543,19 +650,17 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optlen = sizeof(off);
|
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
||||||
err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx) {
|
if (rx) {
|
||||||
rx_map = xsk_mmap(NULL, off.rx.desc +
|
rx_map = mmap(NULL, off.rx.desc +
|
||||||
xsk->config.rx_size * sizeof(struct xdp_desc),
|
xsk->config.rx_size * sizeof(struct xdp_desc),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||||
MAP_SHARED | MAP_POPULATE,
|
xsk->fd, XDP_PGOFF_RX_RING);
|
||||||
xsk->fd, XDP_PGOFF_RX_RING);
|
|
||||||
if (rx_map == MAP_FAILED) {
|
if (rx_map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
@@ -565,16 +670,16 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
rx->size = xsk->config.rx_size;
|
rx->size = xsk->config.rx_size;
|
||||||
rx->producer = rx_map + off.rx.producer;
|
rx->producer = rx_map + off.rx.producer;
|
||||||
rx->consumer = rx_map + off.rx.consumer;
|
rx->consumer = rx_map + off.rx.consumer;
|
||||||
|
rx->flags = rx_map + off.rx.flags;
|
||||||
rx->ring = rx_map + off.rx.desc;
|
rx->ring = rx_map + off.rx.desc;
|
||||||
}
|
}
|
||||||
xsk->rx = rx;
|
xsk->rx = rx;
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
tx_map = xsk_mmap(NULL, off.tx.desc +
|
tx_map = mmap(NULL, off.tx.desc +
|
||||||
xsk->config.tx_size * sizeof(struct xdp_desc),
|
xsk->config.tx_size * sizeof(struct xdp_desc),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||||
MAP_SHARED | MAP_POPULATE,
|
xsk->fd, XDP_PGOFF_TX_RING);
|
||||||
xsk->fd, XDP_PGOFF_TX_RING);
|
|
||||||
if (tx_map == MAP_FAILED) {
|
if (tx_map == MAP_FAILED) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_mmap_rx;
|
goto out_mmap_rx;
|
||||||
@@ -584,6 +689,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
tx->size = xsk->config.tx_size;
|
tx->size = xsk->config.tx_size;
|
||||||
tx->producer = tx_map + off.tx.producer;
|
tx->producer = tx_map + off.tx.producer;
|
||||||
tx->consumer = tx_map + off.tx.consumer;
|
tx->consumer = tx_map + off.tx.consumer;
|
||||||
|
tx->flags = tx_map + off.tx.flags;
|
||||||
tx->ring = tx_map + off.tx.desc;
|
tx->ring = tx_map + off.tx.desc;
|
||||||
tx->cached_cons = xsk->config.tx_size;
|
tx->cached_cons = xsk->config.tx_size;
|
||||||
}
|
}
|
||||||
@@ -592,7 +698,12 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
sxdp.sxdp_family = PF_XDP;
|
sxdp.sxdp_family = PF_XDP;
|
||||||
sxdp.sxdp_ifindex = xsk->ifindex;
|
sxdp.sxdp_ifindex = xsk->ifindex;
|
||||||
sxdp.sxdp_queue_id = xsk->queue_id;
|
sxdp.sxdp_queue_id = xsk->queue_id;
|
||||||
sxdp.sxdp_flags = xsk->config.bind_flags;
|
if (umem->refcount > 1) {
|
||||||
|
sxdp.sxdp_flags = XDP_SHARED_UMEM;
|
||||||
|
sxdp.sxdp_shared_umem_fd = umem->fd;
|
||||||
|
} else {
|
||||||
|
sxdp.sxdp_flags = xsk->config.bind_flags;
|
||||||
|
}
|
||||||
|
|
||||||
err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp));
|
err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp));
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -602,15 +713,6 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
|
|
||||||
xsk->prog_fd = -1;
|
xsk->prog_fd = -1;
|
||||||
|
|
||||||
optlen = sizeof(opts);
|
|
||||||
err = getsockopt(xsk->fd, SOL_XDP, XDP_OPTIONS, &opts, &optlen);
|
|
||||||
if (err) {
|
|
||||||
err = -errno;
|
|
||||||
goto out_mmap_tx;
|
|
||||||
}
|
|
||||||
|
|
||||||
xsk->zc = opts.flags & XDP_OPTIONS_ZEROCOPY;
|
|
||||||
|
|
||||||
if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
||||||
err = xsk_setup_xdp_prog(xsk);
|
err = xsk_setup_xdp_prog(xsk);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -639,7 +741,6 @@ out_xsk_alloc:
|
|||||||
int xsk_umem__delete(struct xsk_umem *umem)
|
int xsk_umem__delete(struct xsk_umem *umem)
|
||||||
{
|
{
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
socklen_t optlen;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!umem)
|
if (!umem)
|
||||||
@@ -648,8 +749,7 @@ int xsk_umem__delete(struct xsk_umem *umem)
|
|||||||
if (umem->refcount)
|
if (umem->refcount)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
optlen = sizeof(off);
|
err = xsk_get_mmap_offsets(umem->fd, &off);
|
||||||
err = getsockopt(umem->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
munmap(umem->fill->ring - off.fr.desc,
|
munmap(umem->fill->ring - off.fr.desc,
|
||||||
off.fr.desc + umem->config.fill_size * sizeof(__u64));
|
off.fr.desc + umem->config.fill_size * sizeof(__u64));
|
||||||
@@ -667,7 +767,6 @@ void xsk_socket__delete(struct xsk_socket *xsk)
|
|||||||
{
|
{
|
||||||
size_t desc_sz = sizeof(struct xdp_desc);
|
size_t desc_sz = sizeof(struct xdp_desc);
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
socklen_t optlen;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!xsk)
|
if (!xsk)
|
||||||
@@ -678,8 +777,7 @@ void xsk_socket__delete(struct xsk_socket *xsk)
|
|||||||
close(xsk->prog_fd);
|
close(xsk->prog_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
optlen = sizeof(off);
|
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
||||||
err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (xsk->rx) {
|
if (xsk->rx) {
|
||||||
munmap(xsk->rx->ring - off.rx.desc,
|
munmap(xsk->rx->ring - off.rx.desc,
|
||||||
|
|||||||
33
src/xsk.h
33
src/xsk.h
@@ -32,6 +32,7 @@ struct name { \
|
|||||||
__u32 *producer; \
|
__u32 *producer; \
|
||||||
__u32 *consumer; \
|
__u32 *consumer; \
|
||||||
void *ring; \
|
void *ring; \
|
||||||
|
__u32 *flags; \
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_XSK_RING(xsk_ring_prod);
|
DEFINE_XSK_RING(xsk_ring_prod);
|
||||||
@@ -76,6 +77,11 @@ xsk_ring_cons__rx_desc(const struct xsk_ring_cons *rx, __u32 idx)
|
|||||||
return &descs[idx & rx->mask];
|
return &descs[idx & rx->mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int xsk_ring_prod__needs_wakeup(const struct xsk_ring_prod *r)
|
||||||
|
{
|
||||||
|
return *r->flags & XDP_RING_NEED_WAKEUP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
||||||
{
|
{
|
||||||
__u32 free_entries = r->cached_cons - r->cached_prod;
|
__u32 free_entries = r->cached_cons - r->cached_prod;
|
||||||
@@ -162,6 +168,21 @@ static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
|||||||
return &((char *)umem_area)[addr];
|
return &((char *)umem_area)[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__extract_addr(__u64 addr)
|
||||||
|
{
|
||||||
|
return addr & XSK_UNALIGNED_BUF_ADDR_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__extract_offset(__u64 addr)
|
||||||
|
{
|
||||||
|
return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)
|
||||||
|
{
|
||||||
|
return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);
|
||||||
|
}
|
||||||
|
|
||||||
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
||||||
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||||
|
|
||||||
@@ -170,12 +191,14 @@ LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
|||||||
#define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
|
#define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
|
||||||
#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
|
#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
|
||||||
#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
|
#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
|
||||||
|
#define XSK_UMEM__DEFAULT_FLAGS 0
|
||||||
|
|
||||||
struct xsk_umem_config {
|
struct xsk_umem_config {
|
||||||
__u32 fill_size;
|
__u32 fill_size;
|
||||||
__u32 comp_size;
|
__u32 comp_size;
|
||||||
__u32 frame_size;
|
__u32 frame_size;
|
||||||
__u32 frame_headroom;
|
__u32 frame_headroom;
|
||||||
|
__u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags for the libbpf_flags field. */
|
/* Flags for the libbpf_flags field. */
|
||||||
@@ -195,6 +218,16 @@ LIBBPF_API int xsk_umem__create(struct xsk_umem **umem,
|
|||||||
struct xsk_ring_prod *fill,
|
struct xsk_ring_prod *fill,
|
||||||
struct xsk_ring_cons *comp,
|
struct xsk_ring_cons *comp,
|
||||||
const struct xsk_umem_config *config);
|
const struct xsk_umem_config *config);
|
||||||
|
LIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||||
|
void *umem_area, __u64 size,
|
||||||
|
struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *config);
|
||||||
|
LIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||||
|
void *umem_area, __u64 size,
|
||||||
|
struct xsk_ring_prod *fill,
|
||||||
|
struct xsk_ring_cons *comp,
|
||||||
|
const struct xsk_umem_config *config);
|
||||||
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
||||||
const char *ifname, __u32 queue_id,
|
const char *ifname, __u32 queue_id,
|
||||||
struct xsk_umem *umem,
|
struct xsk_umem *umem,
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ function info() {
|
|||||||
echo -e "\033[33;1m$1\033[0m"
|
echo -e "\033[33;1m$1\033[0m"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function error() {
|
||||||
|
echo -e "\033[31;1m$1\033[0m"
|
||||||
|
}
|
||||||
|
|
||||||
function docker_exec() {
|
function docker_exec() {
|
||||||
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
||||||
}
|
}
|
||||||
@@ -26,43 +30,43 @@ for phase in "${PHASES[@]}"; do
|
|||||||
SETUP)
|
SETUP)
|
||||||
info "Setup phase"
|
info "Setup phase"
|
||||||
info "Using Debian $DEBIAN_RELEASE"
|
info "Using Debian $DEBIAN_RELEASE"
|
||||||
docker pull debian:$DEBIAN_RELEASE
|
docker pull debian:$DEBIAN_RELEASE
|
||||||
info "Starting container $CONT_NAME"
|
info "Starting container $CONT_NAME"
|
||||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||||
-w /build --privileged=true --name $CONT_NAME \
|
-w /build --privileged=true --name $CONT_NAME \
|
||||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||||
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 build-dep libelf-dev
|
docker_exec apt-get -y build-dep libelf-dev
|
||||||
docker_exec apt-get -y install libelf-dev
|
docker_exec apt-get -y install libelf-dev
|
||||||
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
||||||
;;
|
;;
|
||||||
RUN|RUN_CLANG|RUN_GCC8)
|
RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
||||||
if [[ "$phase" = "RUN_CLANG" ]]; then
|
if [[ "$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" = "RUN_GCC8" ]]; then
|
elif [[ "$phase" = *"GCC8"* ]]; then
|
||||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
||||||
CC="gcc-8"
|
CC="gcc-8"
|
||||||
|
else
|
||||||
|
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
||||||
fi
|
fi
|
||||||
docker_exec mkdir build
|
if [[ "$phase" = *"ASAN"* ]]; then
|
||||||
docker_exec ${CC:-cc} --version
|
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
|
||||||
docker_exec rm -rf build
|
|
||||||
;;
|
|
||||||
RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
|
||||||
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
|
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
|
||||||
CC="clang"
|
|
||||||
elif [[ "$phase" = "RUN_GCC8_ASAN" ]]; then
|
|
||||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
|
||||||
CC="gcc-8"
|
|
||||||
fi
|
fi
|
||||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
docker_exec mkdir build install
|
||||||
docker_exec mkdir build
|
|
||||||
docker_exec ${CC:-cc} --version
|
docker_exec ${CC:-cc} --version
|
||||||
|
info "build"
|
||||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
docker_exec rm -rf build
|
info "ldd build/libbpf.so:"
|
||||||
|
docker_exec ldd build/libbpf.so
|
||||||
|
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||||
|
error "No reference to libelf.so in libbpf.so!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
info "install"
|
||||||
|
docker_exec make -C src OBJDIR=../build DESTDIR=../install install
|
||||||
|
docker_exec rm -rf build install
|
||||||
;;
|
;;
|
||||||
CLEANUP)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
|
|||||||
27
travis-ci/managers/ubuntu.sh
Executable file
27
travis-ci/managers/ubuntu.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
RELEASE="bionic"
|
||||||
|
|
||||||
|
echo "deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse" >>/etc/apt/sources.list
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get -y build-dep libelf-dev
|
||||||
|
apt-get install -y libelf-dev pkg-config
|
||||||
|
|
||||||
|
source "$(dirname $0)/travis_wait.bash"
|
||||||
|
|
||||||
|
cd $REPO_ROOT
|
||||||
|
|
||||||
|
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
||||||
|
mkdir build install
|
||||||
|
cc --version
|
||||||
|
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
|
ldd build/libbpf.so
|
||||||
|
if ! ldd build/libbpf.so | grep -q libelf; then
|
||||||
|
echo "FAIL: No reference to libelf.so in libbpf.so!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
make -C src OBJDIR=../build DESTDIR=../install install
|
||||||
|
rm -rf build install
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
set -x
|
|
||||||
|
|
||||||
apt-get update
|
|
||||||
apt-get -y build-dep libelf-dev
|
|
||||||
apt-get install -y libelf-dev
|
|
||||||
|
|
||||||
source "$(dirname $0)/travis_wait.bash"
|
|
||||||
|
|
||||||
cd $REPO_ROOT
|
|
||||||
|
|
||||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
|
||||||
mkdir build
|
|
||||||
cc --version
|
|
||||||
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
|
||||||
rm -rf build
|
|
||||||
8
travis-ci/vmtest/build_latest_kernel.sh
Executable file
8
travis-ci/vmtest/build_latest_kernel.sh
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
GIT_FETCH_DEPTH="${GIT_FETCH_DEPTH}" ${VMTEST_ROOT}/checkout_latest_kernel.sh $1
|
||||||
|
cd $1
|
||||||
|
cp ${VMTEST_ROOT}/configs/latest.config .config
|
||||||
|
make -j $((4*$(nproc))) olddefconfig all
|
||||||
20
travis-ci/vmtest/build_selftests.sh
Executable file
20
travis-ci/vmtest/build_selftests.sh
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LIBBPF_PATH="${REPO_ROOT}"
|
||||||
|
REPO_PATH="travis-ci/vmtest/bpf-next"
|
||||||
|
make \
|
||||||
|
CLANG=clang-10 \
|
||||||
|
LLC=llc-10 \
|
||||||
|
LLVM_STRIP=llvm-strip-10 \
|
||||||
|
VMLINUX_BTF="${VMLINUX_BTF}" \
|
||||||
|
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||||
|
-j $((4*$(nproc)))
|
||||||
|
mkdir ${LIBBPF_PATH}/selftests
|
||||||
|
cp -R "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||||
|
${LIBBPF_PATH}/selftests
|
||||||
|
cd ${LIBBPF_PATH}
|
||||||
|
rm selftests/bpf/.gitignore
|
||||||
|
git add selftests
|
||||||
|
|
||||||
|
blacklist_path="${VMTEST_ROOT}/configs/blacklist"
|
||||||
|
git add "${blacklist_path}"
|
||||||
24
travis-ci/vmtest/checkout_latest_kernel.sh
Executable file
24
travis-ci/vmtest/checkout_latest_kernel.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
CWD=$(pwd)
|
||||||
|
LIBBPF_PATH=$(pwd)
|
||||||
|
REPO_PATH=$1
|
||||||
|
|
||||||
|
BPF_NEXT_ORIGIN=https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
|
||||||
|
LINUX_SHA=$(cat ${LIBBPF_PATH}/CHECKPOINT-COMMIT)
|
||||||
|
|
||||||
|
echo REPO_PATH = ${REPO_PATH}
|
||||||
|
echo LINUX_SHA = ${LINUX_SHA}
|
||||||
|
|
||||||
|
if [ ! -d "${REPO_PATH}" ]; then
|
||||||
|
mkdir -p ${REPO_PATH}
|
||||||
|
cd ${REPO_PATH}
|
||||||
|
git init
|
||||||
|
git remote add bpf-next ${BPF_NEXT_ORIGIN}
|
||||||
|
git fetch --depth ${GIT_FETCH_DEPTH} bpf-next
|
||||||
|
git reset --hard ${LINUX_SHA}
|
||||||
|
else
|
||||||
|
cd ${REPO_PATH}
|
||||||
|
fi
|
||||||
6
travis-ci/vmtest/configs/INDEX
Normal file
6
travis-ci/vmtest/configs/INDEX
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
INDEX https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/INDEX
|
||||||
|
libbpf-vmtest-rootfs-2020.01.10.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.01.10.tar.zst
|
||||||
|
vmlinux-5.5.0-rc6.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0-rc6.zst
|
||||||
|
vmlinux-5.5.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0.zst
|
||||||
|
vmlinuz-5.5.0-rc6 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0-rc6
|
||||||
|
vmlinuz-5.5.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0
|
||||||
21
travis-ci/vmtest/configs/blacklist/BLACKLIST-5.5.0
Normal file
21
travis-ci/vmtest/configs/blacklist/BLACKLIST-5.5.0
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
mmap
|
||||||
|
dctcp
|
||||||
|
cubic
|
||||||
|
bpf_tcp_ca
|
||||||
|
bpf_verif_scale
|
||||||
|
cgroup_attach
|
||||||
|
pinning
|
||||||
|
send_signal_tracepoint_thread
|
||||||
|
test_syncookie
|
||||||
|
select_reuseport
|
||||||
|
send_signal
|
||||||
|
sockopt_inherit
|
||||||
|
strobemeta_nounroll2
|
||||||
|
stacktrace_build_id
|
||||||
|
tp_attach_query
|
||||||
|
tcp_rtt
|
||||||
|
task_fd_query_tp
|
||||||
|
stacktrace_map
|
||||||
|
test_global_funcs
|
||||||
|
skb_ctx
|
||||||
|
fexit_bpf2bpf
|
||||||
18
travis-ci/vmtest/configs/blacklist/BLACKLIST-5.5.0-rc6
Normal file
18
travis-ci/vmtest/configs/blacklist/BLACKLIST-5.5.0-rc6
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
mmap
|
||||||
|
dctcp
|
||||||
|
cubic
|
||||||
|
bpf_tcp_ca
|
||||||
|
bpf_verif_scale
|
||||||
|
cgroup_attach
|
||||||
|
pinning
|
||||||
|
send_signal_tracepoint_thread
|
||||||
|
test_syncookie
|
||||||
|
select_reuseport
|
||||||
|
send_signal
|
||||||
|
sockopt_inherit
|
||||||
|
strobemeta_nounroll2
|
||||||
|
stacktrace_build_id
|
||||||
|
tp_attach_query
|
||||||
|
tcp_rtt
|
||||||
|
task_fd_query_tp
|
||||||
|
stacktrace_map
|
||||||
23
travis-ci/vmtest/configs/blacklist/BLACKLIST-latest
Normal file
23
travis-ci/vmtest/configs/blacklist/BLACKLIST-latest
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
mmap
|
||||||
|
dctcp
|
||||||
|
cubic
|
||||||
|
bpf_tcp_ca
|
||||||
|
bpf_verif_scale
|
||||||
|
cgroup_attach
|
||||||
|
pinning
|
||||||
|
send_signal_tracepoint_thread
|
||||||
|
test_syncookie
|
||||||
|
select_reuseport
|
||||||
|
send_signal
|
||||||
|
sockopt_inherit
|
||||||
|
strobemeta_nounroll2
|
||||||
|
stacktrace_build_id
|
||||||
|
tp_attach_query
|
||||||
|
tcp_rtt
|
||||||
|
task_fd_query_tp
|
||||||
|
stacktrace_map
|
||||||
|
fentry
|
||||||
|
test_overhead
|
||||||
|
kfree_skb
|
||||||
|
fexit_stress
|
||||||
|
fexit_test
|
||||||
4228
travis-ci/vmtest/configs/latest.config
Normal file
4228
travis-ci/vmtest/configs/latest.config
Normal file
File diff suppressed because it is too large
Load Diff
11
travis-ci/vmtest/prepare_selftests.sh
Executable file
11
travis-ci/vmtest/prepare_selftests.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
GIT_FETCH_DEPTH="${GIT_FETCH_DEPTH}" ${VMTEST_ROOT}/checkout_latest_kernel.sh $1
|
||||||
|
|
||||||
|
# Fix runqslower build
|
||||||
|
# TODO(hex@): remove after the patch is merged from bpf to bpf-next tree
|
||||||
|
cd $1
|
||||||
|
wget https://lore.kernel.org/bpf/908498f794661c44dca54da9e09dc0c382df6fcb.1580425879.git.hex@fb.com/t.mbox.gz
|
||||||
|
gunzip t.mbox.gz
|
||||||
|
git apply t.mbox
|
||||||
438
travis-ci/vmtest/run.sh
Executable file
438
travis-ci/vmtest/run.sh
Executable file
@@ -0,0 +1,438 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
trap 'exit 2' ERR
|
||||||
|
|
||||||
|
usage () {
|
||||||
|
USAGE_STRING="usage: $0 [-k KERNELRELEASE|-b DIR] [[-r ROOTFSVERSION] [-fo]|-I] [-Si] [-d DIR] IMG
|
||||||
|
$0 [-k KERNELRELEASE] -l
|
||||||
|
$0 -h
|
||||||
|
|
||||||
|
Run "${PROJECT_NAME}" tests in a virtual machine.
|
||||||
|
|
||||||
|
This exits with status 0 on success, 1 if the virtual machine ran successfully
|
||||||
|
but tests failed, and 2 if we encountered a fatal error.
|
||||||
|
|
||||||
|
This script uses sudo to mount and modify the disk image.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
IMG path of virtual machine disk image to create
|
||||||
|
|
||||||
|
Versions:
|
||||||
|
-k, --kernel=KERNELRELEASE
|
||||||
|
kernel release to test. This is a glob pattern; the
|
||||||
|
newest (sorted by version number) release that matches
|
||||||
|
the pattern is used (default: newest available release)
|
||||||
|
|
||||||
|
-b, --build DIR use the kernel built in the given directory. This option
|
||||||
|
cannot be combined with -k
|
||||||
|
|
||||||
|
-r, --rootfs=ROOTFSVERSION
|
||||||
|
version of root filesystem to use (default: newest
|
||||||
|
available version)
|
||||||
|
|
||||||
|
Setup:
|
||||||
|
-f, --force overwrite IMG if it already exists
|
||||||
|
|
||||||
|
-o, --one-shot one-shot mode. By default, this script saves a clean copy
|
||||||
|
of the downloaded root filesystem image and vmlinux and
|
||||||
|
makes a copy (reflinked, when possible) for executing the
|
||||||
|
virtual machine. This allows subsequent runs to skip
|
||||||
|
downloading these files. If this option is given, the
|
||||||
|
root filesystem image and vmlinux are always
|
||||||
|
re-downloaded and are not saved. This option implies -f
|
||||||
|
|
||||||
|
-s, --setup-cmd setup commands run on VM boot. Whitespace characters
|
||||||
|
should be escaped with preceding '\'.
|
||||||
|
|
||||||
|
-I, --skip-image skip creating the disk image; use the existing one at
|
||||||
|
IMG. This option cannot be combined with -r, -f, or -o
|
||||||
|
|
||||||
|
-S, --skip-source skip copying the source files and init scripts
|
||||||
|
|
||||||
|
Miscellaneous:
|
||||||
|
-i, --interactive interactive mode. Boot the virtual machine into an
|
||||||
|
interactive shell instead of automatically running tests
|
||||||
|
|
||||||
|
-d, --dir=DIR working directory to use for downloading and caching
|
||||||
|
files (default: current working directory)
|
||||||
|
|
||||||
|
-l, --list list available kernel releases instead of running tests.
|
||||||
|
The list may be filtered with -k
|
||||||
|
|
||||||
|
-h, --help display this help message and exit"
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
out)
|
||||||
|
echo "$USAGE_STRING"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
err)
|
||||||
|
echo "$USAGE_STRING" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
TEMP=$(getopt -o 'k:b:r:fos:ISid:lh' --long 'kernel:,build:,rootfs:,force,one-shot,setup-cmd,skip-image,skip-source:,interactive,dir:,list,help' -n "$0" -- "$@")
|
||||||
|
eval set -- "$TEMP"
|
||||||
|
unset TEMP
|
||||||
|
|
||||||
|
unset KERNELRELEASE
|
||||||
|
unset BUILDDIR
|
||||||
|
unset ROOTFSVERSION
|
||||||
|
unset IMG
|
||||||
|
unset SETUPCMD
|
||||||
|
FORCE=0
|
||||||
|
ONESHOT=0
|
||||||
|
SKIPIMG=0
|
||||||
|
SKIPSOURCE=0
|
||||||
|
APPEND=""
|
||||||
|
DIR="$PWD"
|
||||||
|
LIST=0
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-k|--kernel)
|
||||||
|
KERNELRELEASE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-b|--build)
|
||||||
|
BUILDDIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-r|--rootfs)
|
||||||
|
ROOTFSVERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-f|--force)
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-o|--one-shot)
|
||||||
|
ONESHOT=1
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-s|--setup-cmd)
|
||||||
|
SETUPCMD="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-I|--skip-image)
|
||||||
|
SKIPIMG=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-S|--skip-source)
|
||||||
|
SKIPSOURCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-i|--interactive)
|
||||||
|
APPEND=" single"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-d|--dir)
|
||||||
|
DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-l|--list)
|
||||||
|
LIST=1
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage out
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage err
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ -v BUILDDIR ]]; then
|
||||||
|
if [[ -v KERNELRELEASE ]]; then
|
||||||
|
usage err
|
||||||
|
fi
|
||||||
|
elif [[ ! -v KERNELRELEASE ]]; then
|
||||||
|
KERNELRELEASE='*'
|
||||||
|
fi
|
||||||
|
if [[ $SKIPIMG -ne 0 && ( -v ROOTFSVERSION || $FORCE -ne 0 ) ]]; then
|
||||||
|
usage err
|
||||||
|
fi
|
||||||
|
if (( LIST )); then
|
||||||
|
if [[ $# -ne 0 || -v BUILDDIR || -v ROOTFSVERSION || $FORCE -ne 0 ||
|
||||||
|
$SKIPIMG -ne 0 || $SKIPSOURCE -ne 0 || -n $APPEND ]]; then
|
||||||
|
usage err
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ $# -ne 1 ]]; then
|
||||||
|
usage err
|
||||||
|
fi
|
||||||
|
IMG="${!OPTIND}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset URLS
|
||||||
|
cache_urls() {
|
||||||
|
if ! declare -p URLS &> /dev/null; then
|
||||||
|
# This URL contains a mapping from file names to URLs where
|
||||||
|
# those files can be downloaded.
|
||||||
|
declare -gA URLS
|
||||||
|
while IFS=$'\t' read -r name url; do
|
||||||
|
URLS["$name"]="$url"
|
||||||
|
done < <(cat "${VMTEST_ROOT}/configs/INDEX")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
matching_kernel_releases() {
|
||||||
|
local pattern="$1"
|
||||||
|
{
|
||||||
|
for file in "${!URLS[@]}"; do
|
||||||
|
if [[ $file =~ ^vmlinux-(.*).zst$ ]]; then
|
||||||
|
release="${BASH_REMATCH[1]}"
|
||||||
|
case "$release" in
|
||||||
|
$pattern)
|
||||||
|
# sort -V handles rc versions properly
|
||||||
|
# if we use "~" instead of "-".
|
||||||
|
echo "${release//-rc/~rc}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
} | sort -rV | sed 's/~rc/-rc/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
newest_rootfs_version() {
|
||||||
|
{
|
||||||
|
for file in "${!URLS[@]}"; do
|
||||||
|
if [[ $file =~ ^${PROJECT_NAME}-vmtest-rootfs-(.*)\.tar\.zst$ ]]; then
|
||||||
|
echo "${BASH_REMATCH[1]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
} | sort -rV | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
download() {
|
||||||
|
local file="$1"
|
||||||
|
cache_urls
|
||||||
|
if [[ ! -v URLS[$file] ]]; then
|
||||||
|
echo "$file not found" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "Downloading $file..." >&2
|
||||||
|
curl -Lf "${URLS[$file]}" "${@:2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_nocow() {
|
||||||
|
touch "$@"
|
||||||
|
chattr +C "$@" >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cp_img() {
|
||||||
|
set_nocow "$2"
|
||||||
|
cp --reflink=auto "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_rootfs_img() {
|
||||||
|
local path="$1"
|
||||||
|
set_nocow "$path"
|
||||||
|
truncate -s 2G "$path"
|
||||||
|
mkfs.ext4 -q "$path"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_rootfs() {
|
||||||
|
local rootfsversion="$1"
|
||||||
|
local dir="$2"
|
||||||
|
download "${PROJECT_NAME}-vmtest-rootfs-$rootfsversion.tar.zst" |
|
||||||
|
zstd -d | sudo tar -C "$dir" -x
|
||||||
|
}
|
||||||
|
|
||||||
|
if (( LIST )); then
|
||||||
|
cache_urls
|
||||||
|
matching_kernel_releases "$KERNELRELEASE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $FORCE -eq 0 && $SKIPIMG -eq 0 && -e $IMG ]]; then
|
||||||
|
echo "$IMG already exists; use -f to overwrite it or -I to reuse it" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only go to the network if it's actually a glob pattern.
|
||||||
|
if [[ -v BUILDDIR ]]; then
|
||||||
|
KERNELRELEASE="$(make -C "$BUILDDIR" -s kernelrelease)"
|
||||||
|
elif [[ ! $KERNELRELEASE =~ ^([^\\*?[]|\\[*?[])*\\?$ ]]; then
|
||||||
|
# We need to cache the list of URLs outside of the command
|
||||||
|
# substitution, which happens in a subshell.
|
||||||
|
cache_urls
|
||||||
|
KERNELRELEASE="$(matching_kernel_releases "$KERNELRELEASE" | head -1)"
|
||||||
|
if [[ -z $KERNELRELEASE ]]; then
|
||||||
|
echo "No matching kernel release found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ $SKIPIMG -eq 0 && ! -v ROOTFSVERSION ]]; then
|
||||||
|
cache_urls
|
||||||
|
ROOTFSVERSION="$(newest_rootfs_version)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Kernel release: $KERNELRELEASE" >&2
|
||||||
|
if (( SKIPIMG )); then
|
||||||
|
echo "Not extracting root filesystem" >&2
|
||||||
|
else
|
||||||
|
echo "Root filesystem version: $ROOTFSVERSION" >&2
|
||||||
|
fi
|
||||||
|
echo "Disk image: $IMG" >&2
|
||||||
|
|
||||||
|
tmp=
|
||||||
|
ARCH_DIR="$DIR/x86_64"
|
||||||
|
mkdir -p "$ARCH_DIR"
|
||||||
|
mnt="$(mktemp -d -p "$DIR" mnt.XXXXXXXXXX)"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n $tmp ]]; then
|
||||||
|
rm -f "$tmp" || true
|
||||||
|
fi
|
||||||
|
if mountpoint -q "$mnt"; then
|
||||||
|
sudo umount "$mnt" || true
|
||||||
|
fi
|
||||||
|
if [[ -d "$mnt" ]]; then
|
||||||
|
rmdir "$mnt" || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
if [[ -v BUILDDIR ]]; then
|
||||||
|
vmlinuz="$BUILDDIR/$(make -C "$BUILDDIR" -s image_name)"
|
||||||
|
else
|
||||||
|
vmlinuz="${ARCH_DIR}/vmlinuz-${KERNELRELEASE}"
|
||||||
|
if [[ ! -e $vmlinuz ]]; then
|
||||||
|
tmp="$(mktemp "$vmlinuz.XXX.part")"
|
||||||
|
download "vmlinuz-${KERNELRELEASE}" -o "$tmp"
|
||||||
|
mv "$tmp" "$vmlinuz"
|
||||||
|
tmp=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount and set up the rootfs image.
|
||||||
|
if (( ONESHOT )); then
|
||||||
|
rm -f "$IMG"
|
||||||
|
create_rootfs_img "$IMG"
|
||||||
|
sudo mount -o loop "$IMG" "$mnt"
|
||||||
|
download_rootfs "$ROOTFSVERSION" "$mnt"
|
||||||
|
else
|
||||||
|
if (( ! SKIPIMG )); then
|
||||||
|
rootfs_img="${ARCH_DIR}/${PROJECT_NAME}-vmtest-rootfs-${ROOTFSVERSION}.img"
|
||||||
|
|
||||||
|
if [[ ! -e $rootfs_img ]]; then
|
||||||
|
tmp="$(mktemp "$rootfs_img.XXX.part")"
|
||||||
|
set_nocow "$tmp"
|
||||||
|
truncate -s 2G "$tmp"
|
||||||
|
mkfs.ext4 -q "$tmp"
|
||||||
|
sudo mount -o loop "$tmp" "$mnt"
|
||||||
|
|
||||||
|
download_rootfs "$ROOTFSVERSION" "$mnt"
|
||||||
|
|
||||||
|
sudo umount "$mnt"
|
||||||
|
mv "$tmp" "$rootfs_img"
|
||||||
|
tmp=
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$IMG"
|
||||||
|
cp_img "$rootfs_img" "$IMG"
|
||||||
|
fi
|
||||||
|
sudo mount -o loop "$IMG" "$mnt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install vmlinux.
|
||||||
|
vmlinux="$mnt/boot/vmlinux-${KERNELRELEASE}"
|
||||||
|
if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
||||||
|
if [[ -v BUILDDIR ]]; then
|
||||||
|
source_vmlinux="${BUILDDIR}/vmlinux"
|
||||||
|
else
|
||||||
|
source_vmlinux="${ARCH_DIR}/vmlinux-${KERNELRELEASE}"
|
||||||
|
if [[ ! -e $source_vmlinux ]]; then
|
||||||
|
tmp="$(mktemp "$source_vmlinux.XXX.part")"
|
||||||
|
download "vmlinux-${KERNELRELEASE}.zst" | zstd -dfo "$tmp"
|
||||||
|
mv "$tmp" "$source_vmlinux"
|
||||||
|
tmp=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "Copying vmlinux..." >&2
|
||||||
|
sudo rsync -cp --chmod 0644 "$source_vmlinux" "$vmlinux"
|
||||||
|
else
|
||||||
|
# We could use "sudo zstd -o", but let's not run zstd as root with
|
||||||
|
# input from the internet.
|
||||||
|
download "vmlinux-${KERNELRELEASE}.zst" |
|
||||||
|
zstd -d | sudo tee "$vmlinux" > /dev/null
|
||||||
|
sudo chmod 644 "$vmlinux"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIBBPF_PATH="${REPO_ROOT}" \
|
||||||
|
REPO_PATH="travis-ci/vmtest/bpf-next" \
|
||||||
|
VMTEST_ROOT="${VMTEST_ROOT}" \
|
||||||
|
VMLINUX_BTF=${vmlinux} ${VMTEST_ROOT}/build_selftests.sh
|
||||||
|
|
||||||
|
if (( SKIPSOURCE )); then
|
||||||
|
echo "Not copying source files..." >&2
|
||||||
|
else
|
||||||
|
echo "Copying source files..." >&2
|
||||||
|
|
||||||
|
# Copy the source files in.
|
||||||
|
sudo mkdir -p -m 0755 "$mnt/${PROJECT_NAME}"
|
||||||
|
{
|
||||||
|
if [[ -e .git ]]; then
|
||||||
|
git ls-files -z
|
||||||
|
else
|
||||||
|
tr '\n' '\0' < "${PROJECT_NAME}.egg-info/SOURCES.txt"
|
||||||
|
fi
|
||||||
|
} | sudo rsync --files-from=- -0cpt . "$mnt/${PROJECT_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
setup_script="#!/bin/sh
|
||||||
|
|
||||||
|
echo 'Skipping setup commands'
|
||||||
|
echo 0 > /exitstatus
|
||||||
|
chmod 644 /exitstatus"
|
||||||
|
|
||||||
|
# Create the init scripts.
|
||||||
|
if [[ ! -z SETUPCMD ]]; then
|
||||||
|
# Unescape whitespace characters.
|
||||||
|
setup_cmd=$(sed 's/\(\\\)\([[:space:]]\)/\2/g' <<< "${SETUPCMD}")
|
||||||
|
kernel="${KERNELRELEASE}"
|
||||||
|
if [[ -v BUILDDIR ]]; then kernel='latest'; fi
|
||||||
|
setup_envvars="export KERNEL=${kernel}"
|
||||||
|
setup_script=$(printf "#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo 'Running setup commands'
|
||||||
|
%s
|
||||||
|
%s
|
||||||
|
echo $? > /exitstatus
|
||||||
|
chmod 644 /exitstatus" "${setup_envvars}" "${setup_cmd}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${setup_script}" | sudo tee "$mnt/etc/rcS.d/S50-run-tests" > /dev/null
|
||||||
|
sudo chmod 755 "$mnt/etc/rcS.d/S50-run-tests"
|
||||||
|
|
||||||
|
poweroff_script="#!/bin/sh
|
||||||
|
|
||||||
|
poweroff"
|
||||||
|
echo "${poweroff_script}" | sudo tee "$mnt/etc/rcS.d/S99-poweroff" > /dev/null
|
||||||
|
sudo chmod 755 "$mnt/etc/rcS.d/S99-poweroff"
|
||||||
|
|
||||||
|
sudo umount "$mnt"
|
||||||
|
|
||||||
|
echo "Starting virtual machine..." >&2
|
||||||
|
qemu-system-x86_64 -nodefaults -display none -serial mon:stdio \
|
||||||
|
-cpu kvm64 -enable-kvm -smp "$(nproc)" -m 2G \
|
||||||
|
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
||||||
|
-kernel "$vmlinuz" -append "root=/dev/vda rw console=ttyS0,115200$APPEND"
|
||||||
|
|
||||||
|
sudo mount -o loop "$IMG" "$mnt"
|
||||||
|
if exitstatus="$(cat "$mnt/exitstatus" 2>/dev/null)"; then
|
||||||
|
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
||||||
|
else
|
||||||
|
printf '\nCould not read tests exit status\n' >&2
|
||||||
|
exitstatus=1
|
||||||
|
fi
|
||||||
|
sudo umount "$mnt"
|
||||||
|
exit "$exitstatus"
|
||||||
19
travis-ci/vmtest/run_selftests.sh
Executable file
19
travis-ci/vmtest/run_selftests.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
configs_path='libbpf/travis-ci/vmtest/configs'
|
||||||
|
blacklist_path="$configs_path/blacklist/BLACKLIST-${KERNEL}"
|
||||||
|
if [[ -s "${blacklist_path}" ]]; then
|
||||||
|
BLACKLIST=$(cat "${blacklist_path}" | tr '\n' ',')
|
||||||
|
fi
|
||||||
|
|
||||||
|
whitelist_path="$configs_path/whitelist/WHITELIST-${KERNEL}"
|
||||||
|
if [[ -s "${whitelist_path}" ]]; then
|
||||||
|
WHITELIST=$(cat "${whitelist_path}" | tr '\n' ',')
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd libbpf/selftests/bpf
|
||||||
|
|
||||||
|
echo TEST_PROGS
|
||||||
|
./test_progs ${BLACKLIST:+-b$BLACKLIST} ${WHITELIST:+-t$WHITELIST}
|
||||||
11
travis-ci/vmtest/setup_example.sh
Executable file
11
travis-ci/vmtest/setup_example.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example of a script run on VM boot.
|
||||||
|
# To execute it in TravisCI set VMTEST_SETUPCMD env var of .travis.yml in
|
||||||
|
# libbpf root folder, e.g.
|
||||||
|
# VMTEST_SETUPCMD="./${PROJECT_NAME}/travis-ci/vmtest/setup_example.sh"
|
||||||
|
|
||||||
|
if [ ! -z "${PROJECT_NAME}" ]; then
|
||||||
|
echo "Running ${PROJECT_NAME} setup scripts..."
|
||||||
|
fi
|
||||||
|
echo "Hello, ${USER}!"
|
||||||
Reference in New Issue
Block a user