mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-15 05:49:07 +08:00
Compare commits
17 Commits
netdata_pa
...
v1.0.1_net
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dac1c4b6a8 | ||
|
|
862b60f205 | ||
|
|
70599f3a1e | ||
|
|
e4f2e6e865 | ||
|
|
74c16e9a0c | ||
|
|
e61e089911 | ||
|
|
b9d46530c3 | ||
|
|
86175df408 | ||
|
|
720324afab | ||
|
|
aea40f7179 | ||
|
|
54a7bc87d5 | ||
|
|
9979463ccf | ||
|
|
b91ca01922 | ||
|
|
8ded7c6db0 | ||
|
|
7df4ea0f0d | ||
|
|
02333ba360 | ||
|
|
6921017d25 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
assets/** export-ignore
|
||||
31
.github/actions/build-selftests/action.yml
vendored
Normal file
31
.github/actions/build-selftests/action.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: 'build-selftests'
|
||||
description: 'Build BPF selftests'
|
||||
inputs:
|
||||
repo-path:
|
||||
description: 'where is the source code'
|
||||
required: true
|
||||
kernel:
|
||||
description: 'kernel version or LATEST'
|
||||
required: true
|
||||
default: 'LATEST'
|
||||
vmlinux:
|
||||
description: 'where is vmlinux file'
|
||||
required: true
|
||||
default: '${{ github.workspace }}/vmlinux'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||
foldable start "Setup Env"
|
||||
sudo apt-get install -y qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev python3-docutils
|
||||
foldable end
|
||||
- shell: bash
|
||||
run: |
|
||||
export KERNEL=${{ inputs.kernel }}
|
||||
export REPO_ROOT="${{ github.workspace }}"
|
||||
export REPO_PATH="${{ inputs.repo-path }}"
|
||||
export VMLINUX_BTF="${{ inputs.vmlinux }}"
|
||||
${{ github.action_path }}/build_selftests.sh
|
||||
42
.github/actions/build-selftests/build_selftests.sh
vendored
Executable file
42
.github/actions/build-selftests/build_selftests.sh
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
THISDIR="$(cd $(dirname $0) && pwd)"
|
||||
|
||||
source ${THISDIR}/helpers.sh
|
||||
|
||||
foldable start prepare_selftests "Building selftests"
|
||||
|
||||
LLVM_VER=16
|
||||
LIBBPF_PATH="${REPO_ROOT}"
|
||||
|
||||
PREPARE_SELFTESTS_SCRIPT=${THISDIR}/prepare_selftests-${KERNEL}.sh
|
||||
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
|
||||
(cd "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" && ${PREPARE_SELFTESTS_SCRIPT})
|
||||
fi
|
||||
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
VMLINUX_H=
|
||||
else
|
||||
VMLINUX_H=${THISDIR}/vmlinux.h
|
||||
fi
|
||||
|
||||
cd ${REPO_ROOT}/${REPO_PATH}
|
||||
make \
|
||||
CLANG=clang-${LLVM_VER} \
|
||||
LLC=llc-${LLVM_VER} \
|
||||
LLVM_STRIP=llvm-strip-${LLVM_VER} \
|
||||
VMLINUX_BTF="${VMLINUX_BTF}" \
|
||||
VMLINUX_H=${VMLINUX_H} \
|
||||
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||
-j $((4*$(nproc))) > /dev/null
|
||||
cd -
|
||||
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
|
||||
|
||||
foldable end prepare_selftests
|
||||
36
.github/actions/build-selftests/helpers.sh
vendored
Normal file
36
.github/actions/build-selftests/helpers.sh
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# $1 - start or end
|
||||
# $2 - fold identifier, no spaces
|
||||
# $3 - fold section description
|
||||
foldable() {
|
||||
local YELLOW='\033[1;33m'
|
||||
local NOCOLOR='\033[0m'
|
||||
if [ $1 = "start" ]; then
|
||||
line="::group::$2"
|
||||
if [ ! -z "${3:-}" ]; then
|
||||
line="$line - ${YELLOW}$3${NOCOLOR}"
|
||||
fi
|
||||
else
|
||||
line="::endgroup::"
|
||||
fi
|
||||
echo -e "$line"
|
||||
}
|
||||
|
||||
__print() {
|
||||
local TITLE=""
|
||||
if [[ -n $2 ]]; then
|
||||
TITLE=" title=$2"
|
||||
fi
|
||||
echo "::$1${TITLE}::$3"
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_error() {
|
||||
__print error $1 $2
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_notice() {
|
||||
__print notice $1 $2
|
||||
}
|
||||
3
.github/actions/build-selftests/prepare_selftests-4.9.0.sh
vendored
Executable file
3
.github/actions/build-selftests/prepare_selftests-4.9.0.sh
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
3
.github/actions/build-selftests/prepare_selftests-5.5.0.sh
vendored
Executable file
3
.github/actions/build-selftests/prepare_selftests-5.5.0.sh
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
188802
.github/actions/build-selftests/vmlinux.h
vendored
188802
.github/actions/build-selftests/vmlinux.h
vendored
File diff suppressed because it is too large
Load Diff
4
.github/actions/setup/action.yml
vendored
4
.github/actions/setup/action.yml
vendored
@@ -6,7 +6,7 @@ runs:
|
||||
- id: variables
|
||||
run: |
|
||||
export REPO_ROOT=$GITHUB_WORKSPACE
|
||||
export CI_ROOT=$REPO_ROOT/ci
|
||||
export CI_ROOT=$REPO_ROOT/travis-ci
|
||||
# this is somewhat ugly, but that is the easiest way to share this code with
|
||||
# arch specific docker
|
||||
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
||||
@@ -16,7 +16,7 @@ runs:
|
||||
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
||||
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
||||
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
||||
echo export CI_ROOT=$REPO_ROOT/ci >> /tmp/ci_setup
|
||||
echo export CI_ROOT=$REPO_ROOT/travis-ci >> /tmp/ci_setup
|
||||
echo export VMTEST_ROOT=$CI_ROOT/vmtest >> /tmp/ci_setup
|
||||
echo 'echo ::endgroup::' >> /tmp/ci_setup
|
||||
shell: bash
|
||||
|
||||
96
.github/actions/vmtest/action.yml
vendored
Normal file
96
.github/actions/vmtest/action.yml
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
name: 'vmtest'
|
||||
description: 'Build + run vmtest'
|
||||
inputs:
|
||||
kernel:
|
||||
description: 'kernel version or LATEST'
|
||||
required: true
|
||||
default: 'LATEST'
|
||||
arch:
|
||||
description: 'what arch to test'
|
||||
required: true
|
||||
default: 'x86_64'
|
||||
pahole:
|
||||
description: 'pahole rev or master'
|
||||
required: true
|
||||
default: 'master'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# setup environment
|
||||
- name: Setup environment
|
||||
uses: libbpf/ci/setup-build-env@master
|
||||
with:
|
||||
pahole: ${{ inputs.pahole }}
|
||||
# 1. download CHECKPOINT kernel source
|
||||
- name: Get checkpoint commit
|
||||
shell: bash
|
||||
run: |
|
||||
cat CHECKPOINT-COMMIT
|
||||
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
||||
- name: Get kernel source at checkpoint
|
||||
uses: libbpf/ci/get-linux-source@master
|
||||
with:
|
||||
repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||
rev: ${{ env.CHECKPOINT }}
|
||||
dest: '${{ github.workspace }}/.kernel'
|
||||
- name: Patch kernel source
|
||||
uses: libbpf/ci/patch-kernel@master
|
||||
with:
|
||||
patches-root: '${{ github.workspace }}/travis-ci/diffs'
|
||||
repo-root: '.kernel'
|
||||
- name: Prepare to build BPF selftests
|
||||
shell: bash
|
||||
run: |
|
||||
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||
foldable start "Prepare building selftest"
|
||||
cd .kernel
|
||||
cat tools/testing/selftests/bpf/config \
|
||||
tools/testing/selftests/bpf/config.${{ inputs.arch }} > .config
|
||||
make olddefconfig && make prepare
|
||||
cd -
|
||||
foldable end
|
||||
# 2. if kernel == LATEST, build kernel image from tree
|
||||
- name: Build kernel image
|
||||
if: ${{ inputs.kernel == 'LATEST' }}
|
||||
shell: bash
|
||||
run: |
|
||||
source $GITHUB_ACTION_PATH/../../../ci/vmtest/helpers.sh
|
||||
foldable start "Build Kernel Image"
|
||||
cd .kernel
|
||||
make -j $((4*$(nproc))) all > /dev/null
|
||||
cp vmlinux ${{ github.workspace }}
|
||||
cd -
|
||||
foldable end
|
||||
# else, just download prebuilt kernel image
|
||||
- name: Download prebuilt kernel
|
||||
if: ${{ inputs.kernel != 'LATEST' }}
|
||||
uses: libbpf/ci/download-vmlinux@master
|
||||
with:
|
||||
kernel: ${{ inputs.kernel }}
|
||||
arch: ${{ inputs.arch }}
|
||||
# 3. build selftests
|
||||
- name: Build BPF selftests
|
||||
uses: ./.github/actions/build-selftests
|
||||
with:
|
||||
repo-path: '.kernel'
|
||||
kernel: ${{ inputs.kernel }}
|
||||
# 4. prepare rootfs
|
||||
- name: prepare rootfs
|
||||
uses: libbpf/ci/prepare-rootfs@master
|
||||
with:
|
||||
project-name: 'libbpf'
|
||||
arch: ${{ inputs.arch }}
|
||||
kernel: ${{ inputs.kernel }}
|
||||
kernel-root: '.kernel'
|
||||
image-output: '/tmp/root.img'
|
||||
# 5. run selftest in QEMU
|
||||
- name: Run selftests
|
||||
env:
|
||||
KERNEL: ${{ inputs.kernel }}
|
||||
REPO_ROOT: ${{ github.workspace }}
|
||||
uses: libbpf/ci/run-qemu@master
|
||||
with:
|
||||
arch: ${{ inputs.arch }}
|
||||
img: '/tmp/root.img'
|
||||
vmlinuz: 'vmlinuz'
|
||||
kernel-root: '.kernel'
|
||||
67
.github/workflows/build.yml
vendored
67
.github/workflows/build.yml
vendored
@@ -23,26 +23,16 @@ jobs:
|
||||
target: RUN
|
||||
- name: ASan+UBSan
|
||||
target: RUN_ASAN
|
||||
- name: clang ASan+UBSan
|
||||
target: RUN_CLANG_ASAN
|
||||
- name: gcc-10 ASan+UBSan
|
||||
target: RUN_GCC10_ASAN
|
||||
- name: clang
|
||||
target: RUN_CLANG
|
||||
- name: clang-14
|
||||
target: RUN_CLANG14
|
||||
- name: clang-15
|
||||
target: RUN_CLANG15
|
||||
- name: clang-16
|
||||
target: RUN_CLANG16
|
||||
- name: clang ASan+UBSan
|
||||
target: RUN_CLANG_ASAN
|
||||
- name: gcc-10
|
||||
target: RUN_GCC10
|
||||
- name: gcc-11
|
||||
target: RUN_GCC11
|
||||
- name: gcc-12
|
||||
target: RUN_GCC12
|
||||
- name: gcc-10 ASan+UBSan
|
||||
target: RUN_GCC10_ASAN
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
@@ -53,7 +43,7 @@ jobs:
|
||||
|
||||
ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
name: Ubuntu Build (${{ matrix.arch }})
|
||||
name: Ubuntu Focal Build (${{ matrix.arch }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -61,32 +51,31 @@ jobs:
|
||||
- arch: aarch64
|
||||
- arch: ppc64le
|
||||
- arch: s390x
|
||||
- arch: amd64
|
||||
- arch: x86
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
image: tonistiigi/binfmt:qemu-v8.1.5
|
||||
|
||||
- uses: ./.github/actions/setup
|
||||
name: Pre-Setup
|
||||
|
||||
- run: source /tmp/ci_setup && sudo -E $CI_ROOT/managers/ubuntu.sh
|
||||
if: matrix.arch == 'amd64'
|
||||
if: matrix.arch == 'x86'
|
||||
name: Setup
|
||||
|
||||
- name: Build in docker
|
||||
if: matrix.arch != 'amd64'
|
||||
run: |
|
||||
cp /tmp/ci_setup ${GITHUB_WORKSPACE}
|
||||
docker run --rm \
|
||||
--platform linux/${{ matrix.arch }} \
|
||||
-v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE} \
|
||||
-e GITHUB_WORKSPACE=${GITHUB_WORKSPACE} \
|
||||
-w /ci/workspace \
|
||||
ubuntu:noble \
|
||||
${GITHUB_WORKSPACE}/ci/build-in-docker.sh
|
||||
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Build in docker
|
||||
if: matrix.arch != 'x86'
|
||||
with:
|
||||
distro:
|
||||
ubuntu20.04
|
||||
arch:
|
||||
${{ matrix.arch }}
|
||||
setup:
|
||||
cp /tmp/ci_setup $GITHUB_WORKSPACE
|
||||
dockerRunArgs: |
|
||||
--volume "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export TZ="America/Los_Angeles"
|
||||
apt-get update -y
|
||||
apt-get install -y tzdata build-essential sudo
|
||||
run: source ${GITHUB_WORKSPACE}/ci_setup && $CI_ROOT/managers/ubuntu.sh
|
||||
|
||||
2
.github/workflows/cifuzz.yml
vendored
2
.github/workflows/cifuzz.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
|
||||
52
.github/workflows/codeql.yml
vendored
52
.github/workflows/codeql.yml
vendored
@@ -1,52 +0,0 @@
|
||||
---
|
||||
# vi: ts=2 sw=2 et:
|
||||
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ matrix.language }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
permissions:
|
||||
actions: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['cpp', 'python']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-extended,security-and-quality
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
source /tmp/ci_setup
|
||||
make -C ./src
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
14
.github/workflows/coverity.yml
vendored
14
.github/workflows/coverity.yml
vendored
@@ -1,30 +1,30 @@
|
||||
name: libbpf-ci-coverity
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
name: Coverity
|
||||
env:
|
||||
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- name: Run coverity
|
||||
if: ${{ env.COVERITY_SCAN_TOKEN }}
|
||||
run: |
|
||||
source "${GITHUB_WORKSPACE}"/ci/vmtest/helpers.sh
|
||||
foldable start "Setup CI env"
|
||||
source /tmp/ci_setup
|
||||
export COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
|
||||
export COVERITY_SCAN_BRANCH_PATTERN=${GITHUB_REF##refs/*/}
|
||||
export TRAVIS_BRANCH=${COVERITY_SCAN_BRANCH_PATTERN}
|
||||
foldable end
|
||||
scripts/coverity.sh
|
||||
env:
|
||||
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
COVERITY_SCAN_PROJECT_NAME: libbpf
|
||||
COVERITY_SCAN_BUILD_COMMAND_PREPEND: 'cd src/'
|
||||
COVERITY_SCAN_BUILD_COMMAND: 'make'
|
||||
|
||||
19
.github/workflows/lint.yml
vendored
19
.github/workflows/lint.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: "lint"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
shellcheck:
|
||||
name: ShellCheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
env:
|
||||
SHELLCHECK_OPTS: --severity=error
|
||||
43
.github/workflows/ondemand.yml
vendored
43
.github/workflows/ondemand.yml
vendored
@@ -3,29 +3,34 @@ name: ondemand
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
arch:
|
||||
default: 'x86_64'
|
||||
kernel-origin:
|
||||
description: 'git repo for linux kernel'
|
||||
default: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||
required: true
|
||||
llvm-version:
|
||||
default: '18'
|
||||
required: true
|
||||
kernel:
|
||||
default: 'LATEST'
|
||||
required: true
|
||||
pahole:
|
||||
kernel-rev:
|
||||
description: 'rev/tag/branch for linux kernel'
|
||||
default: "master"
|
||||
required: true
|
||||
runs-on:
|
||||
default: 'ubuntu-24.04'
|
||||
pahole-origin:
|
||||
description: 'git repo for pahole'
|
||||
default: 'https://git.kernel.org/pub/scm/devel/pahole/pahole.git'
|
||||
required: true
|
||||
pahole-rev:
|
||||
description: 'ref/tag/branch for pahole'
|
||||
default: "master"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
vmtest:
|
||||
name: ${{ inputs.kernel }} kernel llvm-${{ inputs.llvm-version }} pahole@${{ inputs.pahole }}
|
||||
uses: ./.github/workflows/vmtest.yml
|
||||
with:
|
||||
runs_on: ${{ inputs.runs-on }}
|
||||
kernel: ${{ inputs.kernel }}
|
||||
arch: ${{ inputs.arch }}
|
||||
llvm-version: ${{ inputs.llvm-version }}
|
||||
pahole: ${{ inputs.pahole }}
|
||||
runs-on: ubuntu-latest
|
||||
name: vmtest with customized pahole/Kernel
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
with:
|
||||
kernel: 'LATEST'
|
||||
kernel-rev: ${{ github.event.inputs.kernel-rev }}
|
||||
kernel-origin: ${{ github.event.inputs.kernel-origin }}
|
||||
pahole: ${{ github.event.inputs.pahole-rev }}
|
||||
pahole-origin: ${{ github.event.inputs.pahole-origin }}
|
||||
|
||||
20
.github/workflows/pahole.yml
vendored
Normal file
20
.github/workflows/pahole.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: pahole-staging
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
|
||||
jobs:
|
||||
vmtest:
|
||||
runs-on: ubuntu-latest
|
||||
name: Kernel LATEST + staging pahole
|
||||
env:
|
||||
STAGING: tmp.master
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
with:
|
||||
kernel: LATEST
|
||||
pahole: $STAGING
|
||||
40
.github/workflows/test.yml
vendored
40
.github/workflows/test.yml
vendored
@@ -1,36 +1,42 @@
|
||||
name: libbpf-ci
|
||||
|
||||
on:
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
concurrency:
|
||||
concurrency:
|
||||
group: ci-test-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
vmtest:
|
||||
runs-on: ${{ matrix.runs_on }}
|
||||
name: Kernel ${{ matrix.kernel }} on ${{ matrix.runs_on }} + selftests
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- kernel: 'LATEST'
|
||||
runs_on: 'ubuntu-24.04'
|
||||
runs_on: ubuntu-latest
|
||||
arch: 'x86_64'
|
||||
- kernel: '5.5.0'
|
||||
runs_on: ubuntu-latest
|
||||
arch: 'x86_64'
|
||||
- kernel: '4.9.0'
|
||||
runs_on: ubuntu-latest
|
||||
arch: 'x86_64'
|
||||
llvm-version: '18'
|
||||
pahole: 'master'
|
||||
- kernel: 'LATEST'
|
||||
runs_on: 'ubuntu-24.04'
|
||||
arch: 'x86_64'
|
||||
llvm-version: '18'
|
||||
pahole: 'tmp.master'
|
||||
name: Linux ${{ matrix.kernel }} llvm-${{ matrix.llvm-version }}
|
||||
uses: ./.github/workflows/vmtest.yml
|
||||
with:
|
||||
runs_on: ${{ matrix.runs_on }}
|
||||
kernel: ${{ matrix.kernel }}
|
||||
arch: ${{ matrix.arch }}
|
||||
llvm-version: ${{ matrix.llvm-version }}
|
||||
pahole: ${{ matrix.pahole }}
|
||||
runs_on: z15
|
||||
arch: 's390x'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
name: vmtest
|
||||
with:
|
||||
kernel: ${{ matrix.kernel }}
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
117
.github/workflows/vmtest.yml
vendored
117
.github/workflows/vmtest.yml
vendored
@@ -1,117 +0,0 @@
|
||||
name: 'Build kernel and selftests/bpf, run selftests via vmtest'
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs_on:
|
||||
required: true
|
||||
default: 'ubuntu-24.04'
|
||||
type: string
|
||||
arch:
|
||||
description: 'what arch to test'
|
||||
required: true
|
||||
default: 'x86_64'
|
||||
type: string
|
||||
kernel:
|
||||
description: 'kernel version or LATEST'
|
||||
required: true
|
||||
default: 'LATEST'
|
||||
type: string
|
||||
pahole:
|
||||
description: 'pahole rev or branch'
|
||||
required: false
|
||||
default: 'master'
|
||||
type: string
|
||||
llvm-version:
|
||||
description: 'llvm version'
|
||||
required: false
|
||||
default: '18'
|
||||
type: string
|
||||
jobs:
|
||||
vmtest:
|
||||
name: pahole@${{ inputs.pahole }}
|
||||
runs-on: ${{ inputs.runs_on }}
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup environment
|
||||
uses: libbpf/ci/setup-build-env@v3
|
||||
with:
|
||||
pahole: ${{ inputs.pahole }}
|
||||
arch: ${{ inputs.arch }}
|
||||
llvm-version: ${{ inputs.llvm-version }}
|
||||
|
||||
- name: Get checkpoint commit
|
||||
shell: bash
|
||||
run: |
|
||||
cat CHECKPOINT-COMMIT
|
||||
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
||||
|
||||
- name: Get kernel source at checkpoint
|
||||
uses: libbpf/ci/get-linux-source@v3
|
||||
with:
|
||||
repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||
rev: ${{ env.CHECKPOINT }}
|
||||
dest: '${{ github.workspace }}/.kernel'
|
||||
|
||||
- name: Patch kernel source
|
||||
uses: libbpf/ci/patch-kernel@v3
|
||||
with:
|
||||
patches-root: '${{ github.workspace }}/ci/diffs'
|
||||
repo-root: '.kernel'
|
||||
|
||||
- name: Configure kernel build
|
||||
shell: bash
|
||||
run: |
|
||||
cd .kernel
|
||||
cat tools/testing/selftests/bpf/config \
|
||||
tools/testing/selftests/bpf/config.${{ inputs.arch }} > .config
|
||||
# this file might or might not exist depending on kernel version
|
||||
cat tools/testing/selftests/bpf/config.vm >> .config || :
|
||||
make olddefconfig && make prepare
|
||||
cd -
|
||||
|
||||
- name: Build kernel image
|
||||
if: ${{ inputs.kernel == 'LATEST' }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd .kernel
|
||||
make -j $((4*$(nproc))) all
|
||||
cp vmlinux ${{ github.workspace }}
|
||||
cd -
|
||||
|
||||
- name: Download prebuilt kernel
|
||||
if: ${{ inputs.kernel != 'LATEST' }}
|
||||
uses: libbpf/ci/download-vmlinux@v3
|
||||
with:
|
||||
kernel: ${{ inputs.kernel }}
|
||||
arch: ${{ inputs.arch }}
|
||||
|
||||
- name: Build selftests/bpf
|
||||
uses: libbpf/ci/build-selftests@v3
|
||||
env:
|
||||
MAX_MAKE_JOBS: 32
|
||||
VMLINUX_BTF: ${{ github.workspace }}/vmlinux
|
||||
VMLINUX_H: ${{ inputs.kernel != 'LATEST' && format('{0}/.github/actions/build-selftests/vmlinux.h', github.workspace) || '' }}
|
||||
with:
|
||||
arch: ${{ inputs.arch }}
|
||||
kernel-root: ${{ github.workspace }}/.kernel
|
||||
llvm-version: ${{ inputs.llvm-version }}
|
||||
|
||||
- name: Run selftests
|
||||
env:
|
||||
ALLOWLIST_FILE: /tmp/allowlist
|
||||
DENYLIST_FILE: /tmp/denylist
|
||||
KERNEL: ${{ inputs.kernel }}
|
||||
VMLINUX: ${{ github.workspace }}/vmlinux
|
||||
LLVM_VERSION: ${{ inputs.llvm-version }}
|
||||
SELFTESTS_BPF: ${{ github.workspace }}/.kernel/tools/testing/selftests/bpf
|
||||
VMTEST_CONFIGS: ${{ github.workspace }}/ci/vmtest/configs
|
||||
uses: libbpf/ci/run-vmtest@v3
|
||||
with:
|
||||
arch: ${{ inputs.arch }}
|
||||
kbuild-output: ${{ github.workspace }}/.kernel
|
||||
kernel-root: ${{ github.workspace }}/.kernel
|
||||
vmlinuz: ${{ inputs.arch }}/vmlinuz-${{ inputs.kernel }}
|
||||
|
||||
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
|
||||
22
.mailmap
22
.mailmap
@@ -1,22 +0,0 @@
|
||||
Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com>
|
||||
Antoine Tenart <atenart@kernel.org> <antoine.tenart@bootlin.com>
|
||||
Benjamin Tissoires <bentiss@kernel.org> <benjamin.tissoires@redhat.com>
|
||||
Björn Töpel <bjorn@kernel.org> <bjorn.topel@intel.com>
|
||||
Changbin Du <changbin.du@intel.com> <changbin.du@gmail.com>
|
||||
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
||||
Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com>
|
||||
Geliang Tang <geliang@kernel.org> <geliang.tang@suse.com>
|
||||
Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Jakub Kicinski <kuba@kernel.org> <jakub.kicinski@netronome.com>
|
||||
Jesper Dangaard Brouer <hawk@kernel.org> <brouer@redhat.com>
|
||||
Kees Cook <kees@kernel.org> <keescook@chromium.org>
|
||||
Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org>
|
||||
Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>
|
||||
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com>
|
||||
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com>
|
||||
Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com>
|
||||
Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com>
|
||||
Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com>
|
||||
Stanislav Fomichev <sdf@fomichev.me> <sdf@google.com>
|
||||
Vadim Fedorenko <vadim.fedorenko@linux.dev> <vadfed@meta.com>
|
||||
Vadim Fedorenko <vadim.fedorenko@linux.dev> <vfedorenko@novek.ru>
|
||||
@@ -5,11 +5,6 @@
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: "ubuntu-22.04"
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
builder: html
|
||||
@@ -22,5 +17,6 @@ formats:
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: docs/sphinx/requirements.txt
|
||||
- requirements: docs/sphinx/requirements.txt
|
||||
@@ -1 +1 @@
|
||||
b4432656b36e5cc1d50a1f2dc15357543add530e
|
||||
60240bc26114543fcbfcd8a28466e67e77b20388
|
||||
|
||||
@@ -1 +1 @@
|
||||
9325d53fe9adff354b6a93fda5f38c165947da0f
|
||||
87dbdc230d162bf9ee1ac77c8ade178b6b1e199e
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
libbpf
|
||||
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
||||
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
||||
[](https://scan.coverity.com/projects/libbpf)
|
||||
[](https://github.com/libbpf/libbpf/actions?query=workflow%3ACodeQL+branch%3Amaster)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libbpf)
|
||||
[](https://libbpf.readthedocs.io/en/latest/)
|
||||
======
|
||||
|
||||
**This is the official home of the libbpf library.**
|
||||
@@ -145,8 +144,8 @@ Distributions packaging libbpf from this mirror:
|
||||
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
||||
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
||||
- [Arch](https://archlinux.org/packages/core/x86_64/libbpf/)
|
||||
- [Ubuntu](https://packages.ubuntu.com/source/jammy/libbpf)
|
||||
- [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
|
||||
- [Ubuntu](https://packages.ubuntu.com/source/impish/libbpf)
|
||||
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
||||
|
||||
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||
@@ -173,7 +172,7 @@ bpf-next to Github sync
|
||||
=======================
|
||||
|
||||
All the gory details of syncing can be found in `scripts/sync-kernel.sh`
|
||||
script. See [SYNC.md](SYNC.md) for instruction.
|
||||
script.
|
||||
|
||||
Some header files in this repo (`include/linux/*.h`) are reduced versions of
|
||||
their counterpart files at
|
||||
|
||||
281
SYNC.md
281
SYNC.md
@@ -1,281 +0,0 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="assets/libbpf-logo-sideways-darkbg.png" width="40%">
|
||||
<img src="assets/libbpf-logo-sideways.png" width="40%">
|
||||
</picture>
|
||||
|
||||
Libbpf sync
|
||||
===========
|
||||
|
||||
Libbpf *authoritative source code* is developed as part of [bpf-next Linux source
|
||||
tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next) under
|
||||
`tools/lib/bpf` subdirectory and is periodically synced to Github.
|
||||
|
||||
Most of the mundane mechanical things like bpf and bpf-next tree merge, Git
|
||||
history transformation, cherry-picking relevant commits, re-generating
|
||||
auto-generated headers, etc. are taken care by
|
||||
[sync-kernel.sh script](https://github.com/libbpf/libbpf/blob/master/scripts/sync-kernel.sh).
|
||||
But occasionally human needs to do few extra things to make everything work
|
||||
nicely.
|
||||
|
||||
This document goes over the process of syncing libbpf sources from Linux repo
|
||||
to this Github repository. Feel free to contribute fixes and additions if you
|
||||
run into new problems not outlined here.
|
||||
|
||||
Setup expectations
|
||||
------------------
|
||||
|
||||
Sync script has particular expectation of upstream Linux repo setup. It
|
||||
expects that current HEAD of that repo points to bpf-next's master branch and
|
||||
that there is a separate local branch pointing to bpf tree's master branch.
|
||||
This is important, as the script will automatically merge their histories for
|
||||
the purpose of libbpf sync.
|
||||
|
||||
Below, we assume that Linux repo is located at `~/linux`, it's current head is
|
||||
at latest `bpf-next/master`, and libbpf's Github repo is located at
|
||||
`~/libbpf`, checked out to latest commit on `master` branch. It doesn't matter
|
||||
from where to run `sync-kernel.sh` script, but we'll be running it from inside
|
||||
`~/libbpf`.
|
||||
|
||||
```
|
||||
$ cd ~/linux && git remote -v | grep -E '^(bpf|bpf-next)'
|
||||
bpf https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git (fetch)
|
||||
bpf ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git
|
||||
(push)
|
||||
bpf-next
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git (fetch)
|
||||
bpf-next
|
||||
ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git (push)
|
||||
$ git branch -vv | grep -E '^? (master|bpf-master)'
|
||||
* bpf-master 2d311f480b52 [bpf/master] riscv, bpf: Fix patch_text implicit declaration
|
||||
master c8ee37bde402 [bpf-next/master] libbpf: Fix bpf_xdp_query() in old kernels
|
||||
$ git checkout bpf-master && git pull && git checkout master && git pull
|
||||
...
|
||||
$ git log --oneline -n1
|
||||
c8ee37bde402 (HEAD -> master, bpf-next/master) libbpf: Fix bpf_xdp_query() in old kernels
|
||||
$ cd ~/libbpf && git checkout master && git pull
|
||||
Your branch is up to date with 'libbpf/master'.
|
||||
Already up to date.
|
||||
```
|
||||
|
||||
Running setup script
|
||||
--------------------
|
||||
|
||||
First step is to always run `sync-kernel.sh` script. It expects three arguments:
|
||||
|
||||
```
|
||||
$ scripts/sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>
|
||||
```
|
||||
|
||||
Note, that we'll store script's entire output in `/tmp/libbpf-sync.txt` and
|
||||
put it into PR summary later on. **Please store scripts output and include it
|
||||
in PR summary for others to check for anything unexpected and suspicious.**
|
||||
|
||||
```
|
||||
$ scripts/sync-kernel.sh ~/libbpf ~/linux bpf-master | tee /tmp/libbpf-sync.txt
|
||||
Dumping existing libbpf commit signatures...
|
||||
WORKDIR: /home/andriin/libbpf
|
||||
LINUX REPO: /home/andriin/linux
|
||||
LIBBPF REPO: /home/andriin/libbpf
|
||||
...
|
||||
```
|
||||
|
||||
Most of the time this will go very uneventful. One expected case when sync
|
||||
script might require user intervention is if `bpf` tree has some libbpf fixes,
|
||||
which is nowadays not a very frequent occurence. But if that happens, script
|
||||
will show you a diff between expected state as of latest bpf-next and synced
|
||||
Github repo state. And will ask if these changes look good. Please use your
|
||||
best judgement to verify that differences are indeed from expected `bpf` tree
|
||||
fixes. E.g., it might look like below:
|
||||
|
||||
```
|
||||
Comparing list of files...
|
||||
Comparing file contents...
|
||||
--- /home/andriin/linux/include/uapi/linux/netdev.h 2023-02-27 16:54:42.270583372 -0800
|
||||
+++ /home/andriin/libbpf/include/uapi/linux/netdev.h 2023-02-27 16:54:34.615530796 -0800
|
||||
@@ -19,7 +19,7 @@
|
||||
* @NETDEV_XDP_ACT_XSK_ZEROCOPY: This feature informs if netdev supports AF_XDP
|
||||
* in zero copy mode.
|
||||
* @NETDEV_XDP_ACT_HW_OFFLOAD: This feature informs if netdev supports XDP hw
|
||||
- * oflloading.
|
||||
+ * offloading.
|
||||
* @NETDEV_XDP_ACT_RX_SG: This feature informs if netdev implements non-linear
|
||||
* XDP buffer support in the driver napi callback.
|
||||
* @NETDEV_XDP_ACT_NDO_XMIT_SG: This feature informs if netdev implements
|
||||
/home/andriin/linux/include/uapi/linux/netdev.h and /home/andriin/libbpf/include/uapi/linux/netdev.h are different!
|
||||
Unfortunately, there are some inconsistencies, please double check.
|
||||
Does everything look good? [y/N]:
|
||||
```
|
||||
|
||||
If it looks sensible and expected, type `y` and script will proceed.
|
||||
|
||||
If sync is successful, your `~/linux` repo will be left in original state on
|
||||
the original HEAD commit. `~/libbpf` repo will now be on a new branch, named
|
||||
`libbpf-sync-<timestamp>` (e.g., `libbpf-sync-2023-02-28T00-53-40.072Z`).
|
||||
|
||||
Push this branch into your fork of `libbpf/libbpf` Github repo and create a PR:
|
||||
|
||||
```
|
||||
$ git push --set-upstream origin libbpf-sync-2023-02-28T00-53-40.072Z
|
||||
Enumerating objects: 130, done.
|
||||
Counting objects: 100% (115/115), done.
|
||||
Delta compression using up to 80 threads
|
||||
Compressing objects: 100% (28/28), done.
|
||||
Writing objects: 100% (32/32), 5.57 KiB | 1.86 MiB/s, done.
|
||||
Total 32 (delta 21), reused 0 (delta 0), pack-reused 0
|
||||
remote: Resolving deltas: 100% (21/21), completed with 9 local objects.
|
||||
remote:
|
||||
remote: Create a pull request for 'libbpf-sync-2023-02-28T00-53-40.072Z' on GitHub by visiting:
|
||||
remote: https://github.com/anakryiko/libbpf/pull/new/libbpf-sync-2023-02-28T00-53-40.072Z
|
||||
remote:
|
||||
To github.com:anakryiko/libbpf.git
|
||||
* [new branch] libbpf-sync-2023-02-28T00-53-40.072Z -> libbpf-sync-2023-02-28T00-53-40.072Z
|
||||
Branch 'libbpf-sync-2023-02-28T00-53-40.072Z' set up to track remote branch 'libbpf-sync-2023-02-28T00-53-40.072Z' from 'origin'.
|
||||
```
|
||||
|
||||
**Please, adjust PR name to have a properly looking timestamp. Libbpf
|
||||
maintainers will be very thankful for that!**
|
||||
|
||||
By default Github will turn above branch name into PR with subject "Libbpf sync
|
||||
2023 02 28 t00 53 40.072 z". Please fix this into a proper timestamp, e.g.:
|
||||
"Libbpf sync 2023-02-28T00:53:40.072Z". Thank you!
|
||||
|
||||
**Please don't forget to paste contents of /tmp/libbpf-sync.txt into PR
|
||||
summary!**
|
||||
|
||||
Once PR is created, libbpf CI will run a bunch of tests to check that
|
||||
everything is good. In simple cases that would be all you'd need to do. In more
|
||||
complicated cases some extra adjustments might be necessary.
|
||||
|
||||
**Please, keep naming and style consistent.** Prefix CI-related fixes with `ci: `
|
||||
prefix. If you had to modify sync script, prefix it with `sync: `. Also make
|
||||
sure that each such commit has `Signed-off-by: Your Full Name <your@email.com>`,
|
||||
just like you'd do that for Linux upstream patch. Libbpf closely follows kernel
|
||||
conventions and styling, so please help maintaining that.
|
||||
|
||||
Including new sources
|
||||
---------------------
|
||||
|
||||
If entirely new source files (typically `*.c`) were added to the library in the
|
||||
kernel repository, it may be necessary to add these to the build system
|
||||
manually (you may notice linker errors otherwise), because the script cannot
|
||||
handle such changes automatically. To that end, edit `src/Makefile` as
|
||||
necessary. Commit
|
||||
[c2495832ced4](https://github.com/libbpf/libbpf/commit/c2495832ced4239bcd376b9954db38a6addd89ca)
|
||||
is an example of how to go about doing that.
|
||||
|
||||
Similarly, if new public API header files were added, the `Makefile` will need
|
||||
to be adjusted as well.
|
||||
|
||||
Updating allow/deny lists
|
||||
-------------------------
|
||||
|
||||
Libbpf CI intentionally runs a subset of latest BPF selftests on old kernel
|
||||
(4.9 and 5.5, currently). It happens from time to time that some tests that
|
||||
previously were successfully running on old kernels now don't, typically due to
|
||||
reliance on some freshly added kernel feature. It might look something like this in [CI logs](https://github.com/libbpf/libbpf/actions/runs/4206303272/jobs/7299609578#step:4:2733):
|
||||
|
||||
```
|
||||
All error logs:
|
||||
serial_test_xdp_info:FAIL:get_xdp_none errno=2
|
||||
#283 xdp_info:FAIL
|
||||
Summary: 49/166 PASSED, 5 SKIPPED, 1 FAILED
|
||||
```
|
||||
|
||||
In such case we can either work with upstream to fix test to be compatible with
|
||||
old kernels, or we'll have to add a test into a denylist (or remove it from
|
||||
allowlist, like was [done](https://github.com/libbpf/libbpf/commit/ea284299025bf85b85b4923191de6463cd43ccd6)
|
||||
for the case above).
|
||||
|
||||
```
|
||||
$ find . -name '*LIST*'
|
||||
./ci/vmtest/configs/ALLOWLIST-4.9.0
|
||||
./ci/vmtest/configs/DENYLIST-5.5.0
|
||||
./ci/vmtest/configs/DENYLIST-latest.s390x
|
||||
./ci/vmtest/configs/DENYLIST-latest
|
||||
./ci/vmtest/configs/ALLOWLIST-5.5.0
|
||||
```
|
||||
|
||||
Please determine which tests need to be added/removed from which list. And then
|
||||
add that as a separate commit. **Please keep using the same branch name, so
|
||||
that the same PR can be updated.** There is no need to open new PRs for each
|
||||
such fix.
|
||||
|
||||
Regenerating vmlinux.h header
|
||||
-----------------------------
|
||||
|
||||
To compile latest BPF selftests against old kernels, we check in pre-generated
|
||||
[vmlinux.h](https://github.com/libbpf/libbpf/blob/master/.github/actions/build-selftests/vmlinux.h)
|
||||
header file, located at `.github/actions/build-selftests/vmlinux.h`, which
|
||||
contains type definitions from latest upstream kernel. When after libbpf sync
|
||||
upstream BPF selftests require new kernel types, we'd need to regenerate
|
||||
`vmlinux.h` and check it in as well.
|
||||
|
||||
This will looks something like this in [CI logs](https://github.com/libbpf/libbpf/actions/runs/4198939244/jobs/7283214243#step:4:1903):
|
||||
|
||||
```
|
||||
In file included from progs/test_spin_lock_fail.c:5:
|
||||
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:73:53: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||
extern struct bpf_rb_node *bpf_rbtree_remove(struct bpf_rb_root *root,
|
||||
^
|
||||
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:81:35: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||
extern void bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node,
|
||||
^
|
||||
/home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/bpf_experimental.h:90:52: error: declaration of 'struct bpf_rb_root' will not be visible outside of this function [-Werror,-Wvisibility]
|
||||
extern struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root) __ksym;
|
||||
^
|
||||
3 errors generated.
|
||||
make: *** [Makefile:572: /home/runner/work/libbpf/libbpf/.kernel/tools/testing/selftests/bpf/test_spin_lock_fail.bpf.o] Error 1
|
||||
make: *** Waiting for unfinished jobs....
|
||||
Error: Process completed with exit code 2.
|
||||
```
|
||||
|
||||
You'll need to build latest upstream kernel from `bpf-next` tree, using BPF
|
||||
selftest configs. Concat arch-agnostic and arch-specific configs, build kernel,
|
||||
then use bpftool to dump `vmlinux.h`:
|
||||
|
||||
```
|
||||
$ cd ~/linux
|
||||
$ cat tools/testing/selftests/bpf/config \
|
||||
tools/testing/selftests/bpf/config.x86_64 > .config
|
||||
$ make -j$(nproc) olddefconfig all
|
||||
...
|
||||
$ bpftool btf dump file ~/linux/vmlinux format c > ~/libbpf/.github/actions/build-selftests/vmlinux.h
|
||||
$ cd ~/libbpf && git add . && git commit -s
|
||||
```
|
||||
|
||||
Check in generated `vmlinux.h`, don't forget to use `ci: ` commit prefix, add
|
||||
it on top of sync commits. Push to Github and let libbpf CI do the checking for
|
||||
you. See [this commit](https://github.com/libbpf/libbpf/commit/34212c94a64df8eeb1dd5d064630a65e1dfd4c20)
|
||||
for reference.
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If something goes wrong and sync script exits early or is terminated early by
|
||||
user, you might end up with `~/linux` repo on temporary sync-related branch.
|
||||
Don't worry, though, sync script never destroys repo state, it follows
|
||||
"copy-on-write" philosophy and creates new branches where necessary. So it's
|
||||
very easy to restore previous state. So if anything goes wrong, it's easy to
|
||||
start fresh:
|
||||
|
||||
```
|
||||
$ git branch | grep -E 'libbpf-.*Z'
|
||||
libbpf-baseline-2023-02-28T00-43-35.146Z
|
||||
libbpf-bpf-baseline-2023-02-28T00-43-35.146Z
|
||||
libbpf-bpf-tip-2023-02-28T00-43-35.146Z
|
||||
libbpf-squash-base-2023-02-28T00-43-35.146Z
|
||||
* libbpf-squash-tip-2023-02-28T00-43-35.146Z
|
||||
$ git cherry-pick --abort
|
||||
$ git checkout master && git branch | grep -E 'libbpf-.*Z' | xargs git br -D
|
||||
Switched to branch 'master'
|
||||
Your branch is up to date with 'bpf-next/master'.
|
||||
Deleted branch libbpf-baseline-2023-02-28T00-43-35.146Z (was 951bce29c898).
|
||||
Deleted branch libbpf-bpf-baseline-2023-02-28T00-43-35.146Z (was 3a70e0d4c9d7).
|
||||
Deleted branch libbpf-bpf-tip-2023-02-28T00-43-35.146Z (was 2d311f480b52).
|
||||
Deleted branch libbpf-squash-base-2023-02-28T00-43-35.146Z (was 957f109ef883).
|
||||
Deleted branch libbpf-squash-tip-2023-02-28T00-43-35.146Z (was be66130d2339).
|
||||
Deleted branch libbpf-tip-2023-02-28T00-43-35.146Z (was 2d311f480b52).
|
||||
```
|
||||
|
||||
You might need to do the same for your `~/libbpf` repo sometimes, depending at
|
||||
which stage sync script was terminated.
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export TZ="America/Los_Angeles"
|
||||
|
||||
apt-get update -y
|
||||
apt-get install -y tzdata build-essential sudo
|
||||
source ${GITHUB_WORKSPACE}/ci_setup
|
||||
|
||||
$CI_ROOT/managers/ubuntu.sh
|
||||
|
||||
exit 0
|
||||
@@ -1,85 +0,0 @@
|
||||
From e3a4f5092e847ec00e2b66c060f2cef52b8d0177 Mon Sep 17 00:00:00 2001
|
||||
From: Ihor Solodrai <ihor.solodrai@pm.me>
|
||||
Date: Thu, 14 Nov 2024 12:49:34 -0800
|
||||
Subject: [PATCH bpf-next] selftests/bpf: set test path for
|
||||
token/obj_priv_implicit_token_envvar
|
||||
|
||||
token/obj_priv_implicit_token_envvar test may fail in an environment
|
||||
where the process executing tests can not write to the root path.
|
||||
|
||||
Example:
|
||||
https://github.com/libbpf/libbpf/actions/runs/11844507007/job/33007897936
|
||||
|
||||
Change default path used by the test to /tmp/bpf-token-fs, and make it
|
||||
runtime configurable via an environment variable.
|
||||
|
||||
Signed-off-by: Ihor Solodrai <ihor.solodrai@pm.me>
|
||||
---
|
||||
tools/testing/selftests/bpf/prog_tests/token.c | 18 +++++++++++-------
|
||||
1 file changed, 11 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/prog_tests/token.c b/tools/testing/selftests/bpf/prog_tests/token.c
|
||||
index fe86e4fdb89c..39f5414b674b 100644
|
||||
--- a/tools/testing/selftests/bpf/prog_tests/token.c
|
||||
+++ b/tools/testing/selftests/bpf/prog_tests/token.c
|
||||
@@ -828,8 +828,11 @@ static int userns_obj_priv_btf_success(int mnt_fd, struct token_lsm *lsm_skel)
|
||||
return validate_struct_ops_load(mnt_fd, true /* should succeed */);
|
||||
}
|
||||
|
||||
+static const char* token_bpffs_custom_dir() {
|
||||
+ return getenv("BPF_SELFTESTS_BPF_TOKEN_DIR") ? : "/tmp/bpf-token-fs";
|
||||
+}
|
||||
+
|
||||
#define TOKEN_ENVVAR "LIBBPF_BPF_TOKEN_PATH"
|
||||
-#define TOKEN_BPFFS_CUSTOM "/bpf-token-fs"
|
||||
|
||||
static int userns_obj_priv_implicit_token(int mnt_fd, struct token_lsm *lsm_skel)
|
||||
{
|
||||
@@ -892,6 +895,7 @@ static int userns_obj_priv_implicit_token(int mnt_fd, struct token_lsm *lsm_skel
|
||||
|
||||
static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *lsm_skel)
|
||||
{
|
||||
+ const char *custom_dir = token_bpffs_custom_dir();
|
||||
LIBBPF_OPTS(bpf_object_open_opts, opts);
|
||||
struct dummy_st_ops_success *skel;
|
||||
int err;
|
||||
@@ -909,10 +913,10 @@ static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *l
|
||||
* BPF token implicitly, unless pointed to it through
|
||||
* LIBBPF_BPF_TOKEN_PATH envvar
|
||||
*/
|
||||
- rmdir(TOKEN_BPFFS_CUSTOM);
|
||||
- if (!ASSERT_OK(mkdir(TOKEN_BPFFS_CUSTOM, 0777), "mkdir_bpffs_custom"))
|
||||
+ rmdir(custom_dir);
|
||||
+ if (!ASSERT_OK(mkdir(custom_dir, 0777), "mkdir_bpffs_custom"))
|
||||
goto err_out;
|
||||
- err = sys_move_mount(mnt_fd, "", AT_FDCWD, TOKEN_BPFFS_CUSTOM, MOVE_MOUNT_F_EMPTY_PATH);
|
||||
+ err = sys_move_mount(mnt_fd, "", AT_FDCWD, custom_dir, MOVE_MOUNT_F_EMPTY_PATH);
|
||||
if (!ASSERT_OK(err, "move_mount_bpffs"))
|
||||
goto err_out;
|
||||
|
||||
@@ -925,7 +929,7 @@ static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *l
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
- err = setenv(TOKEN_ENVVAR, TOKEN_BPFFS_CUSTOM, 1 /*overwrite*/);
|
||||
+ err = setenv(TOKEN_ENVVAR, custom_dir, 1 /*overwrite*/);
|
||||
if (!ASSERT_OK(err, "setenv_token_path"))
|
||||
goto err_out;
|
||||
|
||||
@@ -951,11 +955,11 @@ static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *l
|
||||
if (!ASSERT_ERR(err, "obj_empty_token_path_load"))
|
||||
goto err_out;
|
||||
|
||||
- rmdir(TOKEN_BPFFS_CUSTOM);
|
||||
+ rmdir(custom_dir);
|
||||
unsetenv(TOKEN_ENVVAR);
|
||||
return 0;
|
||||
err_out:
|
||||
- rmdir(TOKEN_BPFFS_CUSTOM);
|
||||
+ rmdir(custom_dir);
|
||||
unsetenv(TOKEN_ENVVAR);
|
||||
return -EINVAL;
|
||||
}
|
||||
--
|
||||
2.47.0
|
||||
|
||||
35
ci/diffs/001-fix-oob-write-in-test_verifier.diff
Normal file
35
ci/diffs/001-fix-oob-write-in-test_verifier.diff
Normal file
@@ -0,0 +1,35 @@
|
||||
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
||||
To: bpf@vger.kernel.org
|
||||
Cc: Alexei Starovoitov <ast@kernel.org>,
|
||||
Daniel Borkmann <daniel@iogearbox.net>,
|
||||
Andrii Nakryiko <andrii@kernel.org>
|
||||
Subject: [PATCH bpf-next] selftests/bpf: Fix OOB write in test_verifier
|
||||
Date: Tue, 14 Dec 2021 07:18:00 +0530 [thread overview]
|
||||
Message-ID: <20211214014800.78762-1-memxor@gmail.com> (raw)
|
||||
|
||||
The commit referenced below added fixup_map_timer support (to create a
|
||||
BPF map containing timers), but failed to increase the size of the
|
||||
map_fds array, leading to out of bounds write. Fix this by changing
|
||||
MAX_NR_MAPS to 22.
|
||||
|
||||
Fixes: e60e6962c503 ("selftests/bpf: Add tests for restricted helpers")
|
||||
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
||||
---
|
||||
tools/testing/selftests/bpf/test_verifier.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
|
||||
index ad5d30bafd93..33e2ecb3bef9 100644
|
||||
--- a/tools/testing/selftests/bpf/test_verifier.c
|
||||
+++ b/tools/testing/selftests/bpf/test_verifier.c
|
||||
@@ -54,7 +54,7 @@
|
||||
#define MAX_INSNS BPF_MAXINSNS
|
||||
#define MAX_TEST_INSNS 1000000
|
||||
#define MAX_FIXUPS 8
|
||||
-#define MAX_NR_MAPS 21
|
||||
+#define MAX_NR_MAPS 22
|
||||
#define MAX_TEST_RUNS 8
|
||||
#define POINTER_VALUE 0xcafe4all
|
||||
#define TEST_DATA_LEN 64
|
||||
--
|
||||
2.34.1
|
||||
@@ -1,69 +0,0 @@
|
||||
From bd06a13f44e15e2e83561ea165061c445a15bd9e Mon Sep 17 00:00:00 2001
|
||||
From: Song Liu <song@kernel.org>
|
||||
Date: Thu, 27 Mar 2025 11:55:28 -0700
|
||||
Subject: [PATCH 4000/4002] selftests/bpf: Fix tests after fields reorder in
|
||||
struct file
|
||||
|
||||
The change in struct file [1] moved f_ref to the 3rd cache line.
|
||||
It made *(u64 *)file dereference invalid from the verifier point of view,
|
||||
because btf_struct_walk() walks into f_lock field, which is 4-byte long.
|
||||
|
||||
Fix the selftests to deference the file pointer as a 4-byte access.
|
||||
|
||||
[1] commit e249056c91a2 ("fs: place f_ref to 3rd cache line in struct file to resolve false sharing")
|
||||
Reported-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Song Liu <song@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20250327185528.1740787-1-song@kernel.org
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
tools/testing/selftests/bpf/progs/test_module_attach.c | 2 +-
|
||||
tools/testing/selftests/bpf/progs/test_subprogs_extable.c | 6 +++---
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/progs/test_module_attach.c b/tools/testing/selftests/bpf/progs/test_module_attach.c
|
||||
index fb07f5773888..7f3c233943b3 100644
|
||||
--- a/tools/testing/selftests/bpf/progs/test_module_attach.c
|
||||
+++ b/tools/testing/selftests/bpf/progs/test_module_attach.c
|
||||
@@ -117,7 +117,7 @@ int BPF_PROG(handle_fexit_ret, int arg, struct file *ret)
|
||||
|
||||
bpf_probe_read_kernel(&buf, 8, ret);
|
||||
bpf_probe_read_kernel(&buf, 8, (char *)ret + 256);
|
||||
- *(volatile long long *)ret;
|
||||
+ *(volatile int *)ret;
|
||||
*(volatile int *)&ret->f_mode;
|
||||
return 0;
|
||||
}
|
||||
diff --git a/tools/testing/selftests/bpf/progs/test_subprogs_extable.c b/tools/testing/selftests/bpf/progs/test_subprogs_extable.c
|
||||
index e2a21fbd4e44..dcac69f5928a 100644
|
||||
--- a/tools/testing/selftests/bpf/progs/test_subprogs_extable.c
|
||||
+++ b/tools/testing/selftests/bpf/progs/test_subprogs_extable.c
|
||||
@@ -21,7 +21,7 @@ static __u64 test_cb(struct bpf_map *map, __u32 *key, __u64 *val, void *data)
|
||||
SEC("fexit/bpf_testmod_return_ptr")
|
||||
int BPF_PROG(handle_fexit_ret_subprogs, int arg, struct file *ret)
|
||||
{
|
||||
- *(volatile long *)ret;
|
||||
+ *(volatile int *)ret;
|
||||
*(volatile int *)&ret->f_mode;
|
||||
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
|
||||
triggered++;
|
||||
@@ -31,7 +31,7 @@ int BPF_PROG(handle_fexit_ret_subprogs, int arg, struct file *ret)
|
||||
SEC("fexit/bpf_testmod_return_ptr")
|
||||
int BPF_PROG(handle_fexit_ret_subprogs2, int arg, struct file *ret)
|
||||
{
|
||||
- *(volatile long *)ret;
|
||||
+ *(volatile int *)ret;
|
||||
*(volatile int *)&ret->f_mode;
|
||||
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
|
||||
triggered++;
|
||||
@@ -41,7 +41,7 @@ int BPF_PROG(handle_fexit_ret_subprogs2, int arg, struct file *ret)
|
||||
SEC("fexit/bpf_testmod_return_ptr")
|
||||
int BPF_PROG(handle_fexit_ret_subprogs3, int arg, struct file *ret)
|
||||
{
|
||||
- *(volatile long *)ret;
|
||||
+ *(volatile int *)ret;
|
||||
*(volatile int *)&ret->f_mode;
|
||||
bpf_for_each_map_elem(&test_array, test_cb, NULL, 0);
|
||||
triggered++;
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
From 8be3a12f9f266aaf3f06f0cfe0e90cfe4d956f3d Mon Sep 17 00:00:00 2001
|
||||
From: Song Liu <song@kernel.org>
|
||||
Date: Fri, 28 Mar 2025 12:31:24 -0700
|
||||
Subject: [PATCH 4001/4002] selftests/bpf: Fix verifier_bpf_fastcall test
|
||||
|
||||
Commit [1] moves percpu data on x86 from address 0x000... to address
|
||||
0xfff...
|
||||
|
||||
Before [1]:
|
||||
|
||||
159020: 0000000000030700 0 OBJECT GLOBAL DEFAULT 23 pcpu_hot
|
||||
|
||||
After [1]:
|
||||
|
||||
152602: ffffffff83a3e034 4 OBJECT GLOBAL DEFAULT 35 pcpu_hot
|
||||
|
||||
As a result, verifier_bpf_fastcall tests should now expect a negative
|
||||
value for pcpu_hot, IOW, the disassemble should show "r=" instead of
|
||||
"w=".
|
||||
|
||||
Fix this in the test.
|
||||
|
||||
Note that, a later change created a new variable "cpu_number" for
|
||||
bpf_get_smp_processor_id() [2]. The inlining logic is updated properly
|
||||
as part of this change, so there is no need to fix anything on the
|
||||
kernel side.
|
||||
|
||||
[1] commit 9d7de2aa8b41 ("x86/percpu/64: Use relative percpu offsets")
|
||||
[2] commit 01c7bc5198e9 ("x86/smp: Move cpu number to percpu hot section")
|
||||
Reported-by: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Song Liu <song@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20250328193124.808784-1-song@kernel.org
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
|
||||
index a9be6ae49454..c258b0722e04 100644
|
||||
--- a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
|
||||
+++ b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
|
||||
@@ -12,7 +12,7 @@ SEC("raw_tp")
|
||||
__arch_x86_64
|
||||
__log_level(4) __msg("stack depth 8")
|
||||
__xlated("4: r5 = 5")
|
||||
-__xlated("5: w0 = ")
|
||||
+__xlated("5: r0 = ")
|
||||
__xlated("6: r0 = &(void __percpu *)(r0)")
|
||||
__xlated("7: r0 = *(u32 *)(r0 +0)")
|
||||
__xlated("8: exit")
|
||||
@@ -704,7 +704,7 @@ SEC("raw_tp")
|
||||
__arch_x86_64
|
||||
__log_level(4) __msg("stack depth 32+0")
|
||||
__xlated("2: r1 = 1")
|
||||
-__xlated("3: w0 =")
|
||||
+__xlated("3: r0 =")
|
||||
__xlated("4: r0 = &(void __percpu *)(r0)")
|
||||
__xlated("5: r0 = *(u32 *)(r0 +0)")
|
||||
/* bpf_loop params setup */
|
||||
@@ -753,7 +753,7 @@ __arch_x86_64
|
||||
__log_level(4) __msg("stack depth 40+0")
|
||||
/* call bpf_get_smp_processor_id */
|
||||
__xlated("2: r1 = 42")
|
||||
-__xlated("3: w0 =")
|
||||
+__xlated("3: r0 =")
|
||||
__xlated("4: r0 = &(void __percpu *)(r0)")
|
||||
__xlated("5: r0 = *(u32 *)(r0 +0)")
|
||||
/* call bpf_get_prandom_u32 */
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
From 07be1f644ff9eeb842fd0490ddd824df0828cb0e Mon Sep 17 00:00:00 2001
|
||||
From: Yonghong Song <yonghong.song@linux.dev>
|
||||
Date: Sun, 30 Mar 2025 20:38:28 -0700
|
||||
Subject: [PATCH 4002/4002] selftests/bpf: Fix verifier_private_stack test
|
||||
failure
|
||||
|
||||
Several verifier_private_stack tests failed with latest bpf-next.
|
||||
For example, for 'Private stack, single prog' subtest, the
|
||||
jitted code:
|
||||
func #0:
|
||||
0: f3 0f 1e fa endbr64
|
||||
4: 0f 1f 44 00 00 nopl (%rax,%rax)
|
||||
9: 0f 1f 00 nopl (%rax)
|
||||
c: 55 pushq %rbp
|
||||
d: 48 89 e5 movq %rsp, %rbp
|
||||
10: f3 0f 1e fa endbr64
|
||||
14: 49 b9 58 74 8a 8f 7d 60 00 00 movabsq $0x607d8f8a7458, %r9
|
||||
1e: 65 4c 03 0c 25 28 c0 48 87 addq %gs:-0x78b73fd8, %r9
|
||||
27: bf 2a 00 00 00 movl $0x2a, %edi
|
||||
2c: 49 89 b9 00 ff ff ff movq %rdi, -0x100(%r9)
|
||||
33: 31 c0 xorl %eax, %eax
|
||||
35: c9 leave
|
||||
36: e9 20 5d 0f e1 jmp 0xffffffffe10f5d5b
|
||||
|
||||
The insn 'addq %gs:-0x78b73fd8, %r9' does not match the expected
|
||||
regex 'addq %gs:0x{{.*}}, %r9' and this caused test failure.
|
||||
|
||||
Fix it by changing '%gs:0x{{.*}}' to '%gs:{{.*}}' to accommodate the
|
||||
possible negative offset. A few other subtests are fixed in a similar way.
|
||||
|
||||
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
|
||||
Link: https://lore.kernel.org/r/20250331033828.365077-1-yonghong.song@linux.dev
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
tools/testing/selftests/bpf/progs/verifier_private_stack.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/progs/verifier_private_stack.c b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
|
||||
index b1fbdf119553..fc91b414364e 100644
|
||||
--- a/tools/testing/selftests/bpf/progs/verifier_private_stack.c
|
||||
+++ b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
|
||||
@@ -27,7 +27,7 @@ __description("Private stack, single prog")
|
||||
__success
|
||||
__arch_x86_64
|
||||
__jited(" movabsq $0x{{.*}}, %r9")
|
||||
-__jited(" addq %gs:0x{{.*}}, %r9")
|
||||
+__jited(" addq %gs:{{.*}}, %r9")
|
||||
__jited(" movl $0x2a, %edi")
|
||||
__jited(" movq %rdi, -0x100(%r9)")
|
||||
__naked void private_stack_single_prog(void)
|
||||
@@ -74,7 +74,7 @@ __success
|
||||
__arch_x86_64
|
||||
/* private stack fp for the main prog */
|
||||
__jited(" movabsq $0x{{.*}}, %r9")
|
||||
-__jited(" addq %gs:0x{{.*}}, %r9")
|
||||
+__jited(" addq %gs:{{.*}}, %r9")
|
||||
__jited(" movl $0x2a, %edi")
|
||||
__jited(" movq %rdi, -0x200(%r9)")
|
||||
__jited(" pushq %r9")
|
||||
@@ -122,7 +122,7 @@ __jited(" pushq %rbp")
|
||||
__jited(" movq %rsp, %rbp")
|
||||
__jited(" endbr64")
|
||||
__jited(" movabsq $0x{{.*}}, %r9")
|
||||
-__jited(" addq %gs:0x{{.*}}, %r9")
|
||||
+__jited(" addq %gs:{{.*}}, %r9")
|
||||
__jited(" pushq %r9")
|
||||
__jited(" callq")
|
||||
__jited(" popq %r9")
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@@ -6,7 +6,7 @@ CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
|
||||
ENV_VARS="${ENV_VARS:-}"
|
||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||
ADDITIONAL_DEPS=(pkgconf)
|
||||
ADDITIONAL_DEPS=(clang pkg-config gcc-10)
|
||||
EXTRA_CFLAGS=""
|
||||
EXTRA_LDFLAGS=""
|
||||
|
||||
@@ -43,35 +43,30 @@ for phase in "${PHASES[@]}"; do
|
||||
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||
docker_exec apt-get -y update
|
||||
docker_exec apt-get -y install aptitude
|
||||
docker_exec aptitude -y install make libz-dev libelf-dev
|
||||
docker_exec aptitude -y build-dep libelf-dev
|
||||
docker_exec aptitude -y install libelf-dev
|
||||
docker_exec aptitude -y install "${ADDITIONAL_DEPS[@]}"
|
||||
echo -e "::endgroup::"
|
||||
;;
|
||||
RUN|RUN_CLANG|RUN_CLANG14|RUN_CLANG15|RUN_CLANG16|RUN_GCC10|RUN_GCC11|RUN_GCC12|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
||||
RUN|RUN_CLANG|RUN_GCC10|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
||||
CC="cc"
|
||||
if [[ "$phase" =~ "RUN_CLANG(\d+)(_ASAN)?" ]]; then
|
||||
ENV_VARS="-e CC=clang-${BASH_REMATCH[1]} -e CXX=clang++-${BASH_REMATCH[1]}"
|
||||
CC="clang-${BASH_REMATCH[1]}"
|
||||
elif [[ "$phase" = *"CLANG"* ]]; then
|
||||
if [[ "$phase" = *"CLANG"* ]]; then
|
||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||
CC="clang"
|
||||
elif [[ "$phase" =~ "RUN_GCC(\d+)(_ASAN)?" ]]; then
|
||||
ENV_VARS="-e CC=gcc-${BASH_REMATCH[1]} -e CXX=g++-${BASH_REMATCH[1]}"
|
||||
CC="gcc-${BASH_REMATCH[1]}"
|
||||
elif [[ "$phase" = *"GCC10"* ]]; then
|
||||
ENV_VARS="-e CC=gcc-10 -e CXX=g++-10"
|
||||
CC="gcc-10"
|
||||
else
|
||||
EXTRA_CFLAGS="${EXTRA_CFLAGS} -Wno-stringop-truncation"
|
||||
fi
|
||||
if [[ "$phase" = *"ASAN"* ]]; then
|
||||
EXTRA_CFLAGS="${EXTRA_CFLAGS} -fsanitize=address,undefined"
|
||||
EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -fsanitize=address,undefined"
|
||||
fi
|
||||
if [[ "$CC" != "cc" ]]; then
|
||||
docker_exec aptitude -y install "$CC"
|
||||
else
|
||||
docker_exec aptitude -y install gcc
|
||||
fi
|
||||
docker_exec mkdir build install
|
||||
docker_exec ${CC} --version
|
||||
info "build"
|
||||
docker_exec make -j$((4*$(nproc))) EXTRA_CFLAGS="${EXTRA_CFLAGS}" EXTRA_LDFLAGS="${EXTRA_LDFLAGS}" -C ./src -B OBJDIR=../build
|
||||
docker_exec make -j$((4*$(nproc))) EXTRA_CFLAGS="${EXTRA_CFLAGS}" EXTRA_LDFLAGS="${EXTRA_LDFLAGS}" -C ./src -B OBJDIR=../build
|
||||
info "ldd build/libbpf.so:"
|
||||
docker_exec ldd build/libbpf.so
|
||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||
|
||||
107
ci/rootfs/mkrootfs_arch.sh
Executable file
107
ci/rootfs/mkrootfs_arch.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is based on drgn script for generating Arch Linux bootstrap
|
||||
# images.
|
||||
# https://github.com/osandov/drgn/blob/master/scripts/vmtest/mkrootfs.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage () {
|
||||
USAGE_STRING="usage: $0 [NAME]
|
||||
$0 -h
|
||||
|
||||
Build an Arch Linux root filesystem image for testing libbpf in a virtual
|
||||
machine.
|
||||
|
||||
The image is generated as a zstd-compressed tarball.
|
||||
|
||||
This must be run as root, as most of the installation is done in a chroot.
|
||||
|
||||
Arguments:
|
||||
NAME name of generated image file (default:
|
||||
libbpf-vmtest-rootfs-\$DATE.tar.zst)
|
||||
|
||||
Options:
|
||||
-h display this help message and exit"
|
||||
|
||||
case "$1" in
|
||||
out)
|
||||
echo "$USAGE_STRING"
|
||||
exit 0
|
||||
;;
|
||||
err)
|
||||
echo "$USAGE_STRING" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
while getopts "h" OPT; do
|
||||
case "$OPT" in
|
||||
h)
|
||||
usage out
|
||||
;;
|
||||
*)
|
||||
usage err
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ $OPTIND -eq $# ]]; then
|
||||
NAME="${!OPTIND}"
|
||||
elif [[ $OPTIND -gt $# ]]; then
|
||||
NAME="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
||||
else
|
||||
usage err
|
||||
fi
|
||||
|
||||
pacman_conf=
|
||||
root=
|
||||
trap 'rm -rf "$pacman_conf" "$root"' EXIT
|
||||
pacman_conf="$(mktemp -p "$PWD")"
|
||||
cat > "$pacman_conf" << "EOF"
|
||||
[options]
|
||||
Architecture = x86_64
|
||||
CheckSpace
|
||||
SigLevel = Required DatabaseOptional
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
[community]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
EOF
|
||||
root="$(mktemp -d -p "$PWD")"
|
||||
|
||||
packages=(
|
||||
busybox
|
||||
# libbpf dependencies.
|
||||
libelf
|
||||
zlib
|
||||
# selftests test_progs dependencies.
|
||||
binutils
|
||||
elfutils
|
||||
ethtool
|
||||
glibc
|
||||
iproute2
|
||||
# selftests test_verifier dependencies.
|
||||
libcap
|
||||
)
|
||||
|
||||
pacstrap -C "$pacman_conf" -cGM "$root" "${packages[@]}"
|
||||
|
||||
# Remove unnecessary files from the chroot.
|
||||
|
||||
# We don't need the pacman databases anymore.
|
||||
rm -rf "$root/var/lib/pacman/sync/"
|
||||
# We don't need D, Fortran, or Go.
|
||||
rm -f "$root/usr/lib/libgdruntime."* \
|
||||
"$root/usr/lib/libgphobos."* \
|
||||
"$root/usr/lib/libgfortran."* \
|
||||
"$root/usr/lib/libgo."*
|
||||
# We don't need any documentation.
|
||||
rm -rf "$root/usr/share/{doc,help,man,texinfo}"
|
||||
|
||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
||||
|
||||
tar -C "$root" -c . | zstd -T0 -19 -o "$NAME"
|
||||
chmod 644 "$NAME"
|
||||
52
ci/rootfs/mkrootfs_debian.sh
Executable file
52
ci/rootfs/mkrootfs_debian.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# This script builds a Debian root filesystem image for testing libbpf in a
|
||||
# virtual machine. Requires debootstrap >= 1.0.95 and zstd.
|
||||
|
||||
# Use e.g. ./mkrootfs_debian.sh --arch=s390x to generate a rootfs for a
|
||||
# foreign architecture. Requires configured binfmt_misc, e.g. using
|
||||
# Debian/Ubuntu's qemu-user-binfmt package or
|
||||
# https://github.com/multiarch/qemu-user-static.
|
||||
|
||||
set -e -u -x -o pipefail
|
||||
|
||||
# Check whether we are root now in order to avoid confusing errors later.
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "$0 must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a working directory and schedule its deletion.
|
||||
root=$(mktemp -d -p "$PWD")
|
||||
trap 'rm -r "$root"' EXIT
|
||||
|
||||
# Install packages.
|
||||
packages=(
|
||||
binutils
|
||||
busybox
|
||||
elfutils
|
||||
ethtool
|
||||
iproute2
|
||||
iptables
|
||||
libcap2
|
||||
libelf1
|
||||
strace
|
||||
zlib1g
|
||||
)
|
||||
packages=$(IFS=, && echo "${packages[*]}")
|
||||
debootstrap --include="$packages" --variant=minbase "$@" bookworm "$root"
|
||||
|
||||
# Remove the init scripts (tests use their own). Also remove various
|
||||
# unnecessary files in order to save space.
|
||||
rm -rf \
|
||||
"$root"/etc/rcS.d \
|
||||
"$root"/usr/share/{doc,info,locale,man,zoneinfo} \
|
||||
"$root"/var/cache/apt/archives/* \
|
||||
"$root"/var/lib/apt/lists/*
|
||||
|
||||
# Apply common tweaks.
|
||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
||||
|
||||
# Save the result.
|
||||
name="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
||||
rm -f "$name"
|
||||
tar -C "$root" -c . | zstd -T0 -19 -o "$name"
|
||||
61
ci/rootfs/mkrootfs_tweak.sh
Executable file
61
ci/rootfs/mkrootfs_tweak.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
# This script prepares a mounted root filesystem for testing libbpf in a virtual
|
||||
# machine.
|
||||
set -e -u -x -o pipefail
|
||||
root=$1
|
||||
shift
|
||||
|
||||
chroot "${root}" /bin/busybox --install
|
||||
|
||||
cat > "$root/etc/inittab" << "EOF"
|
||||
::sysinit:/etc/init.d/rcS
|
||||
::ctrlaltdel:/sbin/reboot
|
||||
::shutdown:/sbin/swapoff -a
|
||||
::shutdown:/bin/umount -a -r
|
||||
::restart:/sbin/init
|
||||
EOF
|
||||
chmod 644 "$root/etc/inittab"
|
||||
|
||||
mkdir -m 755 -p "$root/etc/init.d" "$root/etc/rcS.d"
|
||||
cat > "$root/etc/rcS.d/S10-mount" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
/bin/mount proc /proc -t proc
|
||||
|
||||
# Mount devtmpfs if not mounted
|
||||
if [[ -z $(/bin/mount -t devtmpfs) ]]; then
|
||||
/bin/mount devtmpfs /dev -t devtmpfs
|
||||
fi
|
||||
|
||||
/bin/mount sysfs /sys -t sysfs
|
||||
/bin/mount bpffs /sys/fs/bpf -t bpf
|
||||
/bin/mount debugfs /sys/kernel/debug -t debugfs
|
||||
|
||||
echo 'Listing currently mounted file systems'
|
||||
/bin/mount
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
||||
|
||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
ip link set lo up
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
||||
|
||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
for path in /etc/rcS.d/S*; do
|
||||
[ -x "$path" ] && "$path"
|
||||
done
|
||||
EOF
|
||||
chmod 755 "$root/etc/init.d/rcS"
|
||||
|
||||
chmod 755 "$root"
|
||||
108
ci/rootfs/s390x-self-hosted-builder/README.md
Normal file
108
ci/rootfs/s390x-self-hosted-builder/README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# IBM Z self-hosted builder
|
||||
|
||||
libbpf CI uses an IBM-provided z15 self-hosted builder. There are no IBM Z
|
||||
builds of GitHub (GH) Actions runner, and stable qemu-user has problems with .NET
|
||||
apps, so the builder runs the x86_64 runner version with qemu-user built from
|
||||
the master branch.
|
||||
|
||||
We are currently supporting runners for the following repositories:
|
||||
* libbpf/libbpf
|
||||
* kernel-patches/bpf
|
||||
* kernel-patches/vmtest
|
||||
|
||||
Below instructions are directly applicable to libbpf, and require minor
|
||||
modifications for kernel-patches repos. Currently, qemu-user-static Docker
|
||||
image is shared between all GitHub runners, but separate actions-runner-\*
|
||||
service / Docker image is created for each runner type.
|
||||
|
||||
## Configuring the builder.
|
||||
|
||||
### Install prerequisites.
|
||||
|
||||
```
|
||||
$ sudo apt install -y docker.io # Ubuntu
|
||||
```
|
||||
|
||||
### Add services.
|
||||
|
||||
```
|
||||
$ sudo cp *.service /etc/systemd/system/
|
||||
$ sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
### Create a config file.
|
||||
|
||||
```
|
||||
$ sudo tee /etc/actions-runner-libbpf
|
||||
repo=<owner>/<name>
|
||||
access_token=<ghp_***>
|
||||
runner_name=<hostname>
|
||||
```
|
||||
|
||||
Access token should have the repo scope, consult
|
||||
https://docs.github.com/en/rest/reference/actions#create-a-registration-token-for-a-repository
|
||||
for details.
|
||||
|
||||
### Autostart the x86_64 emulation support.
|
||||
|
||||
This step is important, you would not be able to build docker container
|
||||
without having this service running. If container build fails, make sure
|
||||
service is running properly.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now qemu-user-static
|
||||
```
|
||||
|
||||
### Autostart the runner.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Rebuilding the image
|
||||
|
||||
In order to update the `iiilinuxibmcom/actions-runner-libbpf` image, e.g. to
|
||||
get the latest OS security fixes, use the following commands:
|
||||
|
||||
```
|
||||
$ sudo docker build \
|
||||
--pull \
|
||||
-f actions-runner-libbpf.Dockerfile \
|
||||
-t iiilinuxibmcom/actions-runner-libbpf \
|
||||
.
|
||||
$ sudo systemctl restart actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Removing persistent data
|
||||
|
||||
The `actions-runner-libbpf` service stores various temporary data, such as
|
||||
runner registration information, work directories and logs, in the
|
||||
`actions-runner-libbpf` volume. In order to remove it and start from scratch,
|
||||
e.g. when upgrading the runner or switching it to a different repository, use
|
||||
the following commands:
|
||||
|
||||
```
|
||||
$ sudo systemctl stop actions-runner-libbpf
|
||||
$ sudo docker rm -f actions-runner-libbpf
|
||||
$ sudo docker volume rm actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
In order to check if service is running, use the following command:
|
||||
|
||||
```
|
||||
$ sudo systemctl status <service name>
|
||||
```
|
||||
|
||||
In order to get logs for service:
|
||||
|
||||
```
|
||||
$ journalctl -u <service name>
|
||||
```
|
||||
|
||||
In order to check which containers are currently active:
|
||||
|
||||
```
|
||||
$ sudo docker ps
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
# Self-Hosted IBM Z Github Actions Runner.
|
||||
|
||||
# Temporary image: amd64 dependencies.
|
||||
FROM amd64/ubuntu:20.04 as ld-prefix
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install ca-certificates libicu66 libssl1.1
|
||||
|
||||
# Main image.
|
||||
FROM s390x/ubuntu:20.04
|
||||
|
||||
# Packages for libbpf testing that are not installed by .github/actions/setup.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install \
|
||||
bc \
|
||||
bison \
|
||||
cmake \
|
||||
cpu-checker \
|
||||
curl \
|
||||
flex \
|
||||
git \
|
||||
jq \
|
||||
linux-image-generic \
|
||||
qemu-system-s390x \
|
||||
rsync \
|
||||
software-properties-common \
|
||||
sudo \
|
||||
tree \
|
||||
iproute2 \
|
||||
iputils-ping
|
||||
|
||||
# amd64 dependencies.
|
||||
COPY --from=ld-prefix / /usr/x86_64-linux-gnu/
|
||||
RUN ln -fs ../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /usr/x86_64-linux-gnu/lib64/
|
||||
RUN ln -fs /etc/resolv.conf /usr/x86_64-linux-gnu/etc/
|
||||
ENV QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
||||
|
||||
# amd64 Github Actions Runner.
|
||||
ARG version=2.296.0
|
||||
RUN useradd -m actions-runner
|
||||
RUN echo "actions-runner ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
||||
RUN echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >>/etc/sudoers
|
||||
RUN usermod -a -G kvm actions-runner
|
||||
USER actions-runner
|
||||
ENV USER=actions-runner
|
||||
WORKDIR /home/actions-runner
|
||||
RUN curl -L https://github.com/actions/runner/releases/download/v${version}/actions-runner-linux-x64-${version}.tar.gz | tar -xz
|
||||
VOLUME /home/actions-runner
|
||||
|
||||
# Scripts.
|
||||
COPY fs/ /
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/usr/bin/actions-runner"]
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Self-Hosted IBM Z Github Actions Runner
|
||||
Wants=qemu-user-static
|
||||
After=qemu-user-static
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--device=/dev/kvm \
|
||||
--env-file=/etc/actions-runner-libbpf \
|
||||
--init \
|
||||
--interactive \
|
||||
--name=actions-runner-libbpf \
|
||||
--rm \
|
||||
--volume=actions-runner-libbpf:/home/actions-runner \
|
||||
iiilinuxibmcom/actions-runner-libbpf
|
||||
ExecStop=/bin/sh -c "docker exec actions-runner-libbpf kill -INT -- -1"
|
||||
ExecStop=/bin/sh -c "docker wait actions-runner-libbpf"
|
||||
ExecStop=/bin/sh -c "docker rm actions-runner-libbpf"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
41
ci/rootfs/s390x-self-hosted-builder/fs/usr/bin/actions-runner
Executable file
41
ci/rootfs/s390x-self-hosted-builder/fs/usr/bin/actions-runner
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Ephemeral runner startup script.
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
#
|
||||
# - repo=<owner>/<name>
|
||||
# - access_token=<ghp_***>
|
||||
# - runner_name=<hostname>
|
||||
|
||||
set -e -u
|
||||
|
||||
# Check the cached registration token.
|
||||
token_file=registration-token.json
|
||||
set +e
|
||||
expires_at=$(jq --raw-output .expires_at "$token_file" 2>/dev/null)
|
||||
status=$?
|
||||
set -e
|
||||
if [[ $status -ne 0 || $(date +%s) -ge $(date -d "$expires_at" +%s) ]]; then
|
||||
# Refresh the cached registration token.
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $access_token" \
|
||||
"https://api.github.com/repos/$repo/actions/runners/registration-token" \
|
||||
-o "$token_file"
|
||||
fi
|
||||
|
||||
# (Re-)register the runner.
|
||||
registration_token=$(jq --raw-output .token "$token_file")
|
||||
./config.sh remove --token "$registration_token" || true
|
||||
./config.sh \
|
||||
--url "https://github.com/$repo" \
|
||||
--token "$registration_token" \
|
||||
--labels z15 \
|
||||
--name "$runner_name" \
|
||||
--ephemeral
|
||||
|
||||
# Run one job.
|
||||
./run.sh
|
||||
35
ci/rootfs/s390x-self-hosted-builder/fs/usr/bin/entrypoint
Executable file
35
ci/rootfs/s390x-self-hosted-builder/fs/usr/bin/entrypoint
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Container entrypoint that waits for all spawned processes.
|
||||
#
|
||||
|
||||
set -e -u
|
||||
|
||||
# /dev/kvm has host permissions, fix it.
|
||||
if [ -e /dev/kvm ]; then
|
||||
sudo chown root:kvm /dev/kvm
|
||||
fi
|
||||
|
||||
# Create a FIFO and start reading from its read end.
|
||||
tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX")
|
||||
trap 'rm -r "$tempdir"' EXIT
|
||||
done="$tempdir/pipe"
|
||||
mkfifo "$done"
|
||||
cat "$done" & waiter=$!
|
||||
|
||||
# Start the workload. Its descendants will inherit the FIFO's write end.
|
||||
status=0
|
||||
if [ "$#" -eq 0 ]; then
|
||||
bash 9>"$done" || status=$?
|
||||
else
|
||||
"$@" 9>"$done" || status=$?
|
||||
fi
|
||||
|
||||
# When the workload and all of its descendants exit, the FIFO's write end will
|
||||
# be closed and `cat "$done"` will exit. Wait until it happens. This is needed
|
||||
# in order to handle SelfUpdater, which the workload may start in background
|
||||
# before exiting.
|
||||
wait "$waiter"
|
||||
|
||||
exit "$status"
|
||||
11
ci/rootfs/s390x-self-hosted-builder/qemu-user-static.service
Normal file
11
ci/rootfs/s390x-self-hosted-builder/qemu-user-static.service
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Support for transparent execution of non-native binaries with QEMU user emulation
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# The source code for iiilinuxibmcom/qemu-user-static is at https://github.com/iii-i/qemu-user-static/tree/v6.1.0-1
|
||||
# TODO: replace it with multiarch/qemu-user-static once version >6.1 is available
|
||||
ExecStart=/usr/bin/docker run --rm --interactive --privileged iiilinuxibmcom/qemu-user-static --reset -p yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
8
ci/vmtest/configs/ALLOWLIST-4.9.0
Normal file
8
ci/vmtest/configs/ALLOWLIST-4.9.0
Normal file
@@ -0,0 +1,8 @@
|
||||
# btf_dump -- need to disable data dump sub-tests
|
||||
core_retro
|
||||
cpu_mask
|
||||
hashmap
|
||||
legacy_printk
|
||||
perf_buffer
|
||||
section_names
|
||||
|
||||
55
ci/vmtest/configs/ALLOWLIST-5.5.0
Normal file
55
ci/vmtest/configs/ALLOWLIST-5.5.0
Normal file
@@ -0,0 +1,55 @@
|
||||
# attach_probe
|
||||
autoload
|
||||
bpf_verif_scale
|
||||
cgroup_attach_autodetach
|
||||
cgroup_attach_override
|
||||
core_autosize
|
||||
core_extern
|
||||
core_read_macros
|
||||
core_reloc
|
||||
core_retro
|
||||
cpu_mask
|
||||
endian
|
||||
get_branch_snapshot
|
||||
get_stackid_cannot_attach
|
||||
global_data
|
||||
global_data_init
|
||||
global_func_args
|
||||
hashmap
|
||||
l4lb_all
|
||||
legacy_printk
|
||||
linked_funcs
|
||||
linked_maps
|
||||
map_lock
|
||||
obj_name
|
||||
perf_buffer
|
||||
perf_event_stackmap
|
||||
pinning
|
||||
pkt_md_access
|
||||
probe_user
|
||||
queue_stack_map
|
||||
raw_tp_writable_reject_nbd_invalid
|
||||
raw_tp_writable_test_run
|
||||
rdonly_maps
|
||||
section_names
|
||||
signal_pending
|
||||
skeleton
|
||||
sockmap_ktls
|
||||
sockopt
|
||||
sockopt_inherit
|
||||
sockopt_multi
|
||||
spinlock
|
||||
stacktrace_map
|
||||
stacktrace_map_raw_tp
|
||||
static_linked
|
||||
task_fd_query_rawtp
|
||||
task_fd_query_tp
|
||||
tc_bpf
|
||||
tcp_estats
|
||||
tcp_rtt
|
||||
tp_attach_query
|
||||
usdt/urand_pid_attach
|
||||
xdp
|
||||
xdp_info
|
||||
xdp_noinline
|
||||
xdp_perf
|
||||
@@ -1,15 +0,0 @@
|
||||
# TEMPORARY
|
||||
btf_dump/btf_dump: syntax
|
||||
kprobe_multi_bench_attach
|
||||
core_reloc/enum64val
|
||||
core_reloc/size___diff_sz
|
||||
core_reloc/type_based___diff_sz
|
||||
test_ima # All of CI is broken on it following 6.3-rc1 merge
|
||||
|
||||
lwt_reroute # crashes kernel after netnext merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy"
|
||||
tc_links_ingress # started failing after net-next merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy"
|
||||
xdp_bonding/xdp_bonding_features # started failing after net merge from 359e54a93ab4 "l2tp: pass correct message length to ip6_append_data"
|
||||
tc_redirect/tc_redirect_dtime # uapi breakage after net-next commit 885c36e59f46 ("net: Re-use and set mono_delivery_time bit for userspace tstamp packets")
|
||||
migrate_reuseport/IPv4 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation
|
||||
migrate_reuseport/IPv6 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation
|
||||
verify_pkcs7_sig # keeps failing
|
||||
118
ci/vmtest/configs/DENYLIST-5.5.0
Normal file
118
ci/vmtest/configs/DENYLIST-5.5.0
Normal file
@@ -0,0 +1,118 @@
|
||||
# This file is not used and is there for historic purposes only.
|
||||
# See ALLOWLIST-5.5.0 instead.
|
||||
|
||||
# PERMANENTLY DISABLED
|
||||
align # verifier output format changed
|
||||
atomics # new atomic operations (v5.12+)
|
||||
atomic_bounds # new atomic operations (v5.12+)
|
||||
bind_perm # changed semantics of return values (v5.12+)
|
||||
bpf_cookie # 5.15+
|
||||
bpf_iter # bpf_iter support is missing
|
||||
bpf_obj_id # bpf_link support missing for GET_OBJ_INFO, GET_FD_BY_ID, etc
|
||||
bpf_tcp_ca # STRUCT_OPS is missing
|
||||
btf_map_in_map # inner map leak fixed in 5.8
|
||||
btf_skc_cls_ingress # v5.10+ functionality
|
||||
cg_storage_multi # v5.9+ functionality
|
||||
cgroup_attach_multi # BPF_F_REPLACE_PROG missing
|
||||
cgroup_link # LINK_CREATE is missing
|
||||
cgroup_skb_sk_lookup # bpf_sk_lookup_tcp() helper is missing
|
||||
check_mtu # missing BPF helper (v5.12+)
|
||||
cls_redirect # bpf_csum_level() helper is missing
|
||||
connect_force_port # cgroup/get{peer,sock}name{4,6} support is missing
|
||||
d_path # v5.10+ feature
|
||||
enable_stats # BPF_ENABLE_STATS support is missing
|
||||
fentry_fexit # bpf_prog_test_tracing missing
|
||||
fentry_test # bpf_prog_test_tracing missing
|
||||
fexit_bpf2bpf # freplace is missing
|
||||
fexit_sleep # relies on bpf_trampoline fix in 5.12+
|
||||
fexit_test # bpf_prog_test_tracing missing
|
||||
flow_dissector # bpf_link-based flow dissector is in 5.8+
|
||||
flow_dissector_reattach
|
||||
for_each # v5.12+
|
||||
get_func_ip_test # v5.15+
|
||||
get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
|
||||
hash_large_key # v5.11+
|
||||
ima # v5.11+
|
||||
kfree_skb # 32-bit pointer arith in test_pkt_access
|
||||
ksyms # __start_BTF has different name
|
||||
kfunc_call # v5.13+
|
||||
link_pinning # bpf_link is missing
|
||||
linked_vars # v5.13+
|
||||
load_bytes_relative # new functionality in 5.8
|
||||
lookup_and_delete # v5.14+
|
||||
map_init # per-CPU LRU missing
|
||||
map_ptr # test uses BPF_MAP_TYPE_RINGBUF, added in 5.8
|
||||
metadata # v5.10+
|
||||
migrate_reuseport # v5.14+
|
||||
mmap # 5.5 kernel is too permissive with re-mmaping
|
||||
modify_return # fmod_ret support is missing
|
||||
module_attach # module BTF support missing (v5.11+)
|
||||
netcnt
|
||||
netns_cookie # v5.15+
|
||||
ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
|
||||
pe_preserve_elems # v5.10+
|
||||
perf_branches # bpf_read_branch_records() helper is missing
|
||||
perf_link # v5.15+
|
||||
pkt_access # 32-bit pointer arith in test_pkt_access
|
||||
probe_read_user_str # kernel bug with garbage bytes at the end
|
||||
prog_run_xattr # 32-bit pointer arith in test_pkt_access
|
||||
raw_tp_test_run # v5.10+
|
||||
recursion # v5.12+
|
||||
ringbuf # BPF_MAP_TYPE_RINGBUF is supported in 5.8+
|
||||
|
||||
# bug in verifier w/ tracking references
|
||||
#reference_tracking/classifier/sk_lookup_success
|
||||
reference_tracking
|
||||
|
||||
select_reuseport # UDP support is missing
|
||||
send_signal # bpf_send_signal_thread() helper is missing
|
||||
sk_assign # bpf_sk_assign helper missing
|
||||
sk_lookup # v5.9+
|
||||
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
||||
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
||||
skb_helpers # helpers added in 5.8+
|
||||
skeleton # creates too big ARRAY map
|
||||
snprintf # v5.13+
|
||||
snprintf_btf # v5.10+
|
||||
sock_fields # v5.10+
|
||||
socket_cookie # v5.12+
|
||||
sockmap_basic # uses new socket fields, 5.8+
|
||||
sockmap_listen # no listen socket supportin SOCKMAP
|
||||
sockopt_sk
|
||||
sockopt_qos_to_cc # v5.15+
|
||||
stacktrace_build_id # v5.9+
|
||||
stack_var_off # v5.12+
|
||||
syscall # v5.14+
|
||||
task_local_storage # v5.12+
|
||||
task_pt_regs # v5.15+
|
||||
tcp_hdr_options # v5.10+, new TCP header options feature in BPF
|
||||
tcpbpf_user # LINK_CREATE is missing
|
||||
tc_redirect # v5.14+
|
||||
test_bpffs # v5.10+, new CONFIG_BPF_PRELOAD=y and CONFIG_BPF_PRELOAD_UMG=y|m
|
||||
test_bprm_opts # v5.11+
|
||||
test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
|
||||
test_local_storage # v5.10+ feature
|
||||
test_lsm # no BPF_LSM support
|
||||
test_overhead # no fmod_ret support
|
||||
test_profiler # needs verifier logic improvements from v5.10+
|
||||
test_skb_pkt_end # v5.11+
|
||||
timer # v5.15+
|
||||
timer_mim # v5.15+
|
||||
trace_ext # v5.10+
|
||||
trace_printk # v5.14+
|
||||
trampoline_count # v5.12+ have lower allowed limits
|
||||
udp_limit # no cgroup/sock_release BPF program type (5.9+)
|
||||
varlen # verifier bug fixed in later kernels
|
||||
vmlinux # hrtimer_nanosleep() signature changed incompatibly
|
||||
xdp_adjust_tail # new XDP functionality added in 5.8
|
||||
xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
|
||||
xdp_bonding # v5.15+
|
||||
xdp_bpf2bpf # freplace is missing
|
||||
xdp_context_test_run # v5.15+
|
||||
xdp_cpumap_attach # v5.9+
|
||||
xdp_devmap_attach # new feature in 5.8
|
||||
xdp_link # v5.9+
|
||||
|
||||
# SUBTESTS FAILING (block entire test until blocking subtests works properly)
|
||||
btf # "size check test", "func (Non zero vlen)"
|
||||
tailcalls # tailcall_bpf2bpf_1, tailcall_bpf2bpf_2, tailcall_bpf2bpf_3
|
||||
@@ -1,13 +0,0 @@
|
||||
decap_sanity # weird failure with decap_sanity_ns netns already existing, TBD
|
||||
empty_skb # waiting the fix in bpf tree to make it to bpf-next
|
||||
bpf_nf/tc-bpf-ct # test consistently failing on x86: https://github.com/libbpf/libbpf/pull/698#issuecomment-1590341200
|
||||
bpf_nf/xdp-ct # test consistently failing on x86: https://github.com/libbpf/libbpf/pull/698#issuecomment-1590341200
|
||||
kprobe_multi_bench_attach # suspected to cause crashes in CI
|
||||
find_vma # test consistently fails on latest kernel, see https://github.com/libbpf/libbpf/issues/754 for details
|
||||
bpf_cookie/perf_event
|
||||
send_signal/send_signal_nmi
|
||||
send_signal/send_signal_nmi_thread
|
||||
|
||||
lwt_reroute # crashes kernel, fix pending upstream
|
||||
tc_links_ingress # fails, same fix is pending upstream
|
||||
tc_redirect # enough is enough, banned for life for flakiness
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
# TEMPORARY until bpf-next -> bpf merge
|
||||
lru_bug # prog 'printk': failed to auto-attach: -524
|
||||
|
||||
# TEMPORARY
|
||||
sockmap_listen/sockhash VSOCK test_vsock_redir
|
||||
usdt/basic # failing verifier due to bounds check after LLVM update
|
||||
usdt/multispec # same as above
|
||||
|
||||
deny_namespace # not yet in bpf denylist
|
||||
tc_redirect/tc_redirect_dtime # very flaky
|
||||
lru_bug # not yet in bpf-next denylist
|
||||
|
||||
# Disabled temporarily for a crash.
|
||||
# https://lore.kernel.org/bpf/c9923c1d-971d-4022-8dc8-1364e929d34c@gmail.com/
|
||||
dummy_st_ops/dummy_init_ptr_arg
|
||||
fexit_bpf2bpf
|
||||
tailcalls
|
||||
trace_ext
|
||||
xdp_bpf2bpf
|
||||
xdp_metadata
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This file is sourced by libbpf/ci/run-vmtest Github Action scripts.
|
||||
|
||||
# $SELFTESTS_BPF and $VMTEST_CONFIGS are set in the workflow, before
|
||||
# libbpf/ci/run-vmtest action is called
|
||||
# See .github/workflows/kernel-test.yml
|
||||
|
||||
ALLOWLIST_FILES=(
|
||||
"${SELFTESTS_BPF}/ALLOWLIST"
|
||||
"${SELFTESTS_BPF}/ALLOWLIST.${ARCH}"
|
||||
"${VMTEST_CONFIGS}/ALLOWLIST"
|
||||
"${VMTEST_CONFIGS}/ALLOWLIST-${KERNEL}"
|
||||
"${VMTEST_CONFIGS}/ALLOWLIST-${KERNEL}.${ARCH}"
|
||||
)
|
||||
|
||||
DENYLIST_FILES=(
|
||||
"${SELFTESTS_BPF}/DENYLIST"
|
||||
"${SELFTESTS_BPF}/DENYLIST.${ARCH}"
|
||||
"${VMTEST_CONFIGS}/DENYLIST"
|
||||
"${VMTEST_CONFIGS}/DENYLIST-${KERNEL}"
|
||||
"${VMTEST_CONFIGS}/DENYLIST-${KERNEL}.${ARCH}"
|
||||
)
|
||||
|
||||
# Export pipe-separated strings, because bash doesn't support array export
|
||||
export SELFTESTS_BPF_ALLOWLIST_FILES=$(IFS="|"; echo "${ALLOWLIST_FILES[*]}")
|
||||
export SELFTESTS_BPF_DENYLIST_FILES=$(IFS="|"; echo "${DENYLIST_FILES[*]}")
|
||||
|
||||
if [[ "${LLVM_VERSION}" -lt 18 ]]; then
|
||||
echo "KERNEL_TEST=test_progs test_progs_no_alu32 test_maps test_verifier" >> $GITHUB_ENV
|
||||
else # all
|
||||
echo "KERNEL_TEST=test_progs test_progs_cpuv4 test_progs_no_alu32 test_maps test_verifier" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
echo "cp -R ${SELFTESTS_BPF} ${GITHUB_WORKSPACE}/selftests"
|
||||
mkdir -p "${GITHUB_WORKSPACE}/selftests"
|
||||
cp -R "${SELFTESTS_BPF}" "${GITHUB_WORKSPACE}/selftests"
|
||||
36
ci/vmtest/helpers.sh
Executable file
36
ci/vmtest/helpers.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
# $1 - start or end
|
||||
# $2 - fold identifier, no spaces
|
||||
# $3 - fold section description
|
||||
foldable() {
|
||||
local YELLOW='\033[1;33m'
|
||||
local NOCOLOR='\033[0m'
|
||||
if [ $1 = "start" ]; then
|
||||
line="::group::$2"
|
||||
if [ ! -z "${3:-}" ]; then
|
||||
line="$line - ${YELLOW}$3${NOCOLOR}"
|
||||
fi
|
||||
else
|
||||
line="::endgroup::"
|
||||
fi
|
||||
echo -e "$line"
|
||||
}
|
||||
|
||||
__print() {
|
||||
local TITLE=""
|
||||
if [[ -n $2 ]]; then
|
||||
TITLE=" title=$2"
|
||||
fi
|
||||
echo "::$1${TITLE}::$3"
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_error() {
|
||||
__print error $1 $2
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_notice() {
|
||||
__print notice $1 $2
|
||||
}
|
||||
87
ci/vmtest/run_selftests.sh
Executable file
87
ci/vmtest/run_selftests.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||
|
||||
ARCH=$(uname -m)
|
||||
|
||||
STATUS_FILE=/exitstatus
|
||||
|
||||
read_lists() {
|
||||
(for path in "$@"; do
|
||||
if [[ -s "$path" ]]; then
|
||||
cat "$path"
|
||||
fi;
|
||||
done) | cut -d'#' -f1 | tr -s ' \t\n' ','
|
||||
}
|
||||
|
||||
test_progs() {
|
||||
if [[ "${KERNEL}" != '4.9.0' ]]; then
|
||||
foldable start test_progs "Testing test_progs"
|
||||
# "&& true" does not change the return code (it is not executed
|
||||
# if the Python script fails), but it prevents exiting on a
|
||||
# failure due to the "set -e".
|
||||
./test_progs ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
||||
echo "test_progs:$?" >> "${STATUS_FILE}"
|
||||
foldable end test_progs
|
||||
fi
|
||||
}
|
||||
|
||||
test_progs_no_alu32() {
|
||||
foldable start test_progs-no_alu32 "Testing test_progs-no_alu32"
|
||||
./test_progs-no_alu32 ${DENYLIST:+-d$DENYLIST} ${ALLOWLIST:+-a$ALLOWLIST} && true
|
||||
echo "test_progs-no_alu32:$?" >> "${STATUS_FILE}"
|
||||
foldable end test_progs-no_alu32
|
||||
}
|
||||
|
||||
test_maps() {
|
||||
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||
foldable start test_maps "Testing test_maps"
|
||||
./test_maps && true
|
||||
echo "test_maps:$?" >> "${STATUS_FILE}"
|
||||
foldable end test_maps
|
||||
fi
|
||||
}
|
||||
|
||||
test_verifier() {
|
||||
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||
foldable start test_verifier "Testing test_verifier"
|
||||
./test_verifier && true
|
||||
echo "test_verifier:$?" >> "${STATUS_FILE}"
|
||||
foldable end test_verifier
|
||||
fi
|
||||
}
|
||||
|
||||
foldable end vm_init
|
||||
|
||||
configs_path=/${PROJECT_NAME}/selftests/bpf
|
||||
local_configs_path=${PROJECT_NAME}/vmtest/configs
|
||||
DENYLIST=$(read_lists \
|
||||
"$configs_path/DENYLIST" \
|
||||
"$configs_path/DENYLIST.${ARCH}" \
|
||||
"$local_configs_path/DENYLIST-${KERNEL}" \
|
||||
"$local_configs_path/DENYLIST-${KERNEL}.${ARCH}" \
|
||||
)
|
||||
ALLOWLIST=$(read_lists \
|
||||
"$configs_path/ALLOWLIST" \
|
||||
"$configs_path/ALLOWLIST.${ARCH}" \
|
||||
"$local_configs_path/ALLOWLIST-${KERNEL}" \
|
||||
"$local_configs_path/ALLOWLIST-${KERNEL}.${ARCH}" \
|
||||
)
|
||||
|
||||
echo "DENYLIST: ${DENYLIST}"
|
||||
echo "ALLOWLIST: ${ALLOWLIST}"
|
||||
|
||||
cd ${PROJECT_NAME}/selftests/bpf
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
test_progs
|
||||
test_progs_no_alu32
|
||||
test_maps
|
||||
test_verifier
|
||||
else
|
||||
for test_name in "$@"; do
|
||||
"${test_name}"
|
||||
done
|
||||
fi
|
||||
@@ -18,7 +18,6 @@ extensions = [
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.imgmath',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx_rtd_theme',
|
||||
'breathe',
|
||||
]
|
||||
|
||||
|
||||
@@ -1,33 +1,21 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
.. _libbpf:
|
||||
|
||||
======
|
||||
libbpf
|
||||
======
|
||||
|
||||
If you are looking to develop BPF applications using the libbpf library, this
|
||||
directory contains important documentation that you should read.
|
||||
|
||||
To get started, it is recommended to begin with the :doc:`libbpf Overview
|
||||
<libbpf_overview>` document, which provides a high-level understanding of the
|
||||
libbpf APIs and their usage. This will give you a solid foundation to start
|
||||
exploring and utilizing the various features of libbpf to develop your BPF
|
||||
applications.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
libbpf_overview
|
||||
API Documentation <https://libbpf.readthedocs.io/en/latest/api.html>
|
||||
program_types
|
||||
libbpf_naming_convention
|
||||
libbpf_build
|
||||
|
||||
This is documentation for libbpf, a userspace library for loading and
|
||||
interacting with bpf programs.
|
||||
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and their
|
||||
application, should be sent to bpf@vger.kernel.org mailing list. You can
|
||||
`subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the mailing list
|
||||
search its `archive <https://lore.kernel.org/bpf/>`_. Please search the archive
|
||||
before asking new questions. It may be that this was already addressed or
|
||||
answered before.
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
||||
their application, should be sent to bpf@vger.kernel.org mailing list.
|
||||
You can `subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the
|
||||
mailing list search its `archive <https://lore.kernel.org/bpf/>`_.
|
||||
Please search the archive before asking new questions. It very well might
|
||||
be that this was already addressed or answered before.
|
||||
|
||||
@@ -83,8 +83,8 @@ This prevents from accidentally exporting a symbol, that is not supposed
|
||||
to be a part of ABI what, in turn, improves both libbpf developer- and
|
||||
user-experiences.
|
||||
|
||||
ABI versioning
|
||||
--------------
|
||||
ABI versionning
|
||||
---------------
|
||||
|
||||
To make future ABI extensions possible libbpf ABI is versioned.
|
||||
Versioning is implemented by ``libbpf.map`` version script that is
|
||||
@@ -148,7 +148,7 @@ API documentation convention
|
||||
The libbpf API is documented via comments above definitions in
|
||||
header files. These comments can be rendered by doxygen and sphinx
|
||||
for well organized html output. This section describes the
|
||||
convention in which these comments should be formatted.
|
||||
convention in which these comments should be formated.
|
||||
|
||||
Here is an example from btf.h:
|
||||
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
libbpf Overview
|
||||
===============
|
||||
|
||||
libbpf is a C-based library containing a BPF loader that takes compiled BPF
|
||||
object files and prepares and loads them into the Linux kernel. libbpf takes the
|
||||
heavy lifting of loading, verifying, and attaching BPF programs to various
|
||||
kernel hooks, allowing BPF application developers to focus only on BPF program
|
||||
correctness and performance.
|
||||
|
||||
The following are the high-level features supported by libbpf:
|
||||
|
||||
* Provides high-level and low-level APIs for user space programs to interact
|
||||
with BPF programs. The low-level APIs wrap all the bpf system call
|
||||
functionality, which is useful when users need more fine-grained control
|
||||
over the interactions between user space and BPF programs.
|
||||
* Provides overall support for the BPF object skeleton generated by bpftool.
|
||||
The skeleton file simplifies the process for the user space programs to access
|
||||
global variables and work with BPF programs.
|
||||
* Provides BPF-side APIS, including BPF helper definitions, BPF maps support,
|
||||
and tracing helpers, allowing developers to simplify BPF code writing.
|
||||
* Supports BPF CO-RE mechanism, enabling BPF developers to write portable
|
||||
BPF programs that can be compiled once and run across different kernel
|
||||
versions.
|
||||
|
||||
This document will delve into the above concepts in detail, providing a deeper
|
||||
understanding of the capabilities and advantages of libbpf and how it can help
|
||||
you develop BPF applications efficiently.
|
||||
|
||||
BPF App Lifecycle and libbpf APIs
|
||||
==================================
|
||||
|
||||
A BPF application consists of one or more BPF programs (either cooperating or
|
||||
completely independent), BPF maps, and global variables. The global
|
||||
variables are shared between all BPF programs, which allows them to cooperate on
|
||||
a common set of data. libbpf provides APIs that user space programs can use to
|
||||
manipulate the BPF programs by triggering different phases of a BPF application
|
||||
lifecycle.
|
||||
|
||||
The following section provides a brief overview of each phase in the BPF life
|
||||
cycle:
|
||||
|
||||
* **Open phase**: In this phase, libbpf parses the BPF
|
||||
object file and discovers BPF maps, BPF programs, and global variables. After
|
||||
a BPF app is opened, user space apps can make additional adjustments
|
||||
(setting BPF program types, if necessary; pre-setting initial values for
|
||||
global variables, etc.) before all the entities are created and loaded.
|
||||
|
||||
* **Load phase**: In the load phase, libbpf creates BPF
|
||||
maps, resolves various relocations, and verifies and loads BPF programs into
|
||||
the kernel. At this point, libbpf validates all the parts of a BPF application
|
||||
and loads the BPF program into the kernel, but no BPF program has yet been
|
||||
executed. After the load phase, it’s possible to set up the initial BPF map
|
||||
state without racing with the BPF program code execution.
|
||||
|
||||
* **Attachment phase**: In this phase, libbpf
|
||||
attaches BPF programs to various BPF hook points (e.g., tracepoints, kprobes,
|
||||
cgroup hooks, network packet processing pipeline, etc.). During this
|
||||
phase, BPF programs perform useful work such as processing
|
||||
packets, or updating BPF maps and global variables that can be read from user
|
||||
space.
|
||||
|
||||
* **Tear down phase**: In the tear down phase,
|
||||
libbpf detaches BPF programs and unloads them from the kernel. BPF maps are
|
||||
destroyed, and all the resources used by the BPF app are freed.
|
||||
|
||||
BPF Object Skeleton File
|
||||
========================
|
||||
|
||||
BPF skeleton is an alternative interface to libbpf APIs for working with BPF
|
||||
objects. Skeleton code abstract away generic libbpf APIs to significantly
|
||||
simplify code for manipulating BPF programs from user space. Skeleton code
|
||||
includes a bytecode representation of the BPF object file, simplifying the
|
||||
process of distributing your BPF code. With BPF bytecode embedded, there are no
|
||||
extra files to deploy along with your application binary.
|
||||
|
||||
You can generate the skeleton header file ``(.skel.h)`` for a specific object
|
||||
file by passing the BPF object to the bpftool. The generated BPF skeleton
|
||||
provides the following custom functions that correspond to the BPF lifecycle,
|
||||
each of them prefixed with the specific object name:
|
||||
|
||||
* ``<name>__open()`` – creates and opens BPF application (``<name>`` stands for
|
||||
the specific bpf object name)
|
||||
* ``<name>__load()`` – instantiates, loads,and verifies BPF application parts
|
||||
* ``<name>__attach()`` – attaches all auto-attachable BPF programs (it’s
|
||||
optional, you can have more control by using libbpf APIs directly)
|
||||
* ``<name>__destroy()`` – detaches all BPF programs and
|
||||
frees up all used resources
|
||||
|
||||
Using the skeleton code is the recommended way to work with bpf programs. Keep
|
||||
in mind, BPF skeleton provides access to the underlying BPF object, so whatever
|
||||
was possible to do with generic libbpf APIs is still possible even when the BPF
|
||||
skeleton is used. It's an additive convenience feature, with no syscalls, and no
|
||||
cumbersome code.
|
||||
|
||||
Other Advantages of Using Skeleton File
|
||||
---------------------------------------
|
||||
|
||||
* BPF skeleton provides an interface for user space programs to work with BPF
|
||||
global variables. The skeleton code memory maps global variables as a struct
|
||||
into user space. The struct interface allows user space programs to initialize
|
||||
BPF programs before the BPF load phase and fetch and update data from user
|
||||
space afterward.
|
||||
|
||||
* The ``skel.h`` file reflects the object file structure by listing out the
|
||||
available maps, programs, etc. BPF skeleton provides direct access to all the
|
||||
BPF maps and BPF programs as struct fields. This eliminates the need for
|
||||
string-based lookups with ``bpf_object_find_map_by_name()`` and
|
||||
``bpf_object_find_program_by_name()`` APIs, reducing errors due to BPF source
|
||||
code and user-space code getting out of sync.
|
||||
|
||||
* The embedded bytecode representation of the object file ensures that the
|
||||
skeleton and the BPF object file are always in sync.
|
||||
|
||||
BPF Helpers
|
||||
===========
|
||||
|
||||
libbpf provides BPF-side APIs that BPF programs can use to interact with the
|
||||
system. The BPF helpers definition allows developers to use them in BPF code as
|
||||
any other plain C function. For example, there are helper functions to print
|
||||
debugging messages, get the time since the system was booted, interact with BPF
|
||||
maps, manipulate network packets, etc.
|
||||
|
||||
For a complete description of what the helpers do, the arguments they take, and
|
||||
the return value, see the `bpf-helpers
|
||||
<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>`_ man page.
|
||||
|
||||
BPF CO-RE (Compile Once – Run Everywhere)
|
||||
=========================================
|
||||
|
||||
BPF programs work in the kernel space and have access to kernel memory and data
|
||||
structures. One limitation that BPF applications come across is the lack of
|
||||
portability across different kernel versions and configurations. `BCC
|
||||
<https://github.com/iovisor/bcc/>`_ is one of the solutions for BPF
|
||||
portability. However, it comes with runtime overhead and a large binary size
|
||||
from embedding the compiler with the application.
|
||||
|
||||
libbpf steps up the BPF program portability by supporting the BPF CO-RE concept.
|
||||
BPF CO-RE brings together BTF type information, libbpf, and the compiler to
|
||||
produce a single executable binary that you can run on multiple kernel versions
|
||||
and configurations.
|
||||
|
||||
To make BPF programs portable libbpf relies on the BTF type information of the
|
||||
running kernel. Kernel also exposes this self-describing authoritative BTF
|
||||
information through ``sysfs`` at ``/sys/kernel/btf/vmlinux``.
|
||||
|
||||
You can generate the BTF information for the running kernel with the following
|
||||
command:
|
||||
|
||||
::
|
||||
|
||||
$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
|
||||
|
||||
The command generates a ``vmlinux.h`` header file with all kernel types
|
||||
(:doc:`BTF types <../btf>`) that the running kernel uses. Including
|
||||
``vmlinux.h`` in your BPF program eliminates dependency on system-wide kernel
|
||||
headers.
|
||||
|
||||
libbpf enables portability of BPF programs by looking at the BPF program’s
|
||||
recorded BTF type and relocation information and matching them to BTF
|
||||
information (vmlinux) provided by the running kernel. libbpf then resolves and
|
||||
matches all the types and fields, and updates necessary offsets and other
|
||||
relocatable data to ensure that BPF program’s logic functions correctly for a
|
||||
specific kernel on the host. BPF CO-RE concept thus eliminates overhead
|
||||
associated with BPF development and allows developers to write portable BPF
|
||||
applications without modifications and runtime source code compilation on the
|
||||
target machine.
|
||||
|
||||
The following code snippet shows how to read the parent field of a kernel
|
||||
``task_struct`` using BPF CO-RE and libbf. The basic helper to read a field in a
|
||||
CO-RE relocatable manner is ``bpf_core_read(dst, sz, src)``, which will read
|
||||
``sz`` bytes from the field referenced by ``src`` into the memory pointed to by
|
||||
``dst``.
|
||||
|
||||
.. code-block:: C
|
||||
:emphasize-lines: 6
|
||||
|
||||
//...
|
||||
struct task_struct *task = (void *)bpf_get_current_task();
|
||||
struct task_struct *parent_task;
|
||||
int err;
|
||||
|
||||
err = bpf_core_read(&parent_task, sizeof(void *), &task->parent);
|
||||
if (err) {
|
||||
/* handle error */
|
||||
}
|
||||
|
||||
/* parent_task contains the value of task->parent pointer */
|
||||
|
||||
In the code snippet, we first get a pointer to the current ``task_struct`` using
|
||||
``bpf_get_current_task()``. We then use ``bpf_core_read()`` to read the parent
|
||||
field of task struct into the ``parent_task`` variable. ``bpf_core_read()`` is
|
||||
just like ``bpf_probe_read_kernel()`` BPF helper, except it records information
|
||||
about the field that should be relocated on the target kernel. i.e, if the
|
||||
``parent`` field gets shifted to a different offset within
|
||||
``struct task_struct`` due to some new field added in front of it, libbpf will
|
||||
automatically adjust the actual offset to the proper value.
|
||||
|
||||
Getting Started with libbpf
|
||||
===========================
|
||||
|
||||
Check out the `libbpf-bootstrap <https://github.com/libbpf/libbpf-bootstrap>`_
|
||||
repository with simple examples of using libbpf to build various BPF
|
||||
applications.
|
||||
|
||||
See also `libbpf API documentation
|
||||
<https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||
|
||||
libbpf and Rust
|
||||
===============
|
||||
|
||||
If you are building BPF applications in Rust, it is recommended to use the
|
||||
`Libbpf-rs <https://github.com/libbpf/libbpf-rs>`_ library instead of bindgen
|
||||
bindings directly to libbpf. Libbpf-rs wraps libbpf functionality in
|
||||
Rust-idiomatic interfaces and provides libbpf-cargo plugin to handle BPF code
|
||||
compilation and skeleton generation. Using Libbpf-rs will make building user
|
||||
space part of the BPF application easier. Note that the BPF program themselves
|
||||
must still be written in plain C.
|
||||
|
||||
libbpf logging
|
||||
==============
|
||||
|
||||
By default, libbpf logs informational and warning messages to stderr. The
|
||||
verbosity of these messages can be controlled by setting the environment
|
||||
variable LIBBPF_LOG_LEVEL to either warn, info, or debug. A custom log
|
||||
callback can be set using ``libbpf_set_print()``.
|
||||
|
||||
Additional Documentation
|
||||
========================
|
||||
|
||||
* `Program types and ELF Sections <https://libbpf.readthedocs.io/en/latest/program_types.html>`_
|
||||
* `API naming convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html>`_
|
||||
* `Building libbpf <https://libbpf.readthedocs.io/en/latest/libbpf_build.html>`_
|
||||
* `API documentation Convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html#api-documentation-convention>`_
|
||||
@@ -1,235 +0,0 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
.. _program_types_and_elf:
|
||||
|
||||
Program Types and ELF Sections
|
||||
==============================
|
||||
|
||||
The table below lists the program types, their attach types where relevant and the ELF section
|
||||
names supported by libbpf for them. The ELF section names follow these rules:
|
||||
|
||||
- ``type`` is an exact match, e.g. ``SEC("socket")``
|
||||
- ``type+`` means it can be either exact ``SEC("type")`` or well-formed ``SEC("type/extras")``
|
||||
with a '``/``' separator between ``type`` and ``extras``.
|
||||
|
||||
When ``extras`` are specified, they provide details of how to auto-attach the BPF program. The
|
||||
format of ``extras`` depends on the program type, e.g. ``SEC("tracepoint/<category>/<name>")``
|
||||
for tracepoints or ``SEC("usdt/<path>:<provider>:<name>")`` for USDT probes. The extras are
|
||||
described in more detail in the footnotes.
|
||||
|
||||
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| Program Type | Attach Type | ELF Section Name | Sleepable |
|
||||
+===========================================+========================================+==================================+===========+
|
||||
| ``BPF_PROG_TYPE_CGROUP_DEVICE`` | ``BPF_CGROUP_DEVICE`` | ``cgroup/dev`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SKB`` | | ``cgroup/skb`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET_EGRESS`` | ``cgroup_skb/egress`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET_INGRESS`` | ``cgroup_skb/ingress`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SOCKOPT`` | ``BPF_CGROUP_GETSOCKOPT`` | ``cgroup/getsockopt`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_SETSOCKOPT`` | ``cgroup/setsockopt`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SOCK_ADDR`` | ``BPF_CGROUP_INET4_BIND`` | ``cgroup/bind4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET4_CONNECT`` | ``cgroup/connect4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET4_GETPEERNAME`` | ``cgroup/getpeername4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET4_GETSOCKNAME`` | ``cgroup/getsockname4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET6_BIND`` | ``cgroup/bind6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET6_CONNECT`` | ``cgroup/connect6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET6_GETPEERNAME`` | ``cgroup/getpeername6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET6_GETSOCKNAME`` | ``cgroup/getsockname6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP4_RECVMSG`` | ``cgroup/recvmsg4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP4_SENDMSG`` | ``cgroup/sendmsg4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_CONNECT`` | ``cgroup/connect_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_SENDMSG`` | ``cgroup/sendmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_RECVMSG`` | ``cgroup/recvmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETPEERNAME`` | ``cgroup/getpeername_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETSOCKNAME`` | ``cgroup/getsockname_unix`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET6_POST_BIND`` | ``cgroup/post_bind6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET_SOCK_CREATE`` | ``cgroup/sock_create`` | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``cgroup/sock`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_INET_SOCK_RELEASE`` | ``cgroup/sock_release`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SYSCTL`` | ``BPF_CGROUP_SYSCTL`` | ``cgroup/sysctl`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_EXT`` | | ``freplace+`` [#fentry]_ | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_FLOW_DISSECTOR`` | ``BPF_FLOW_DISSECTOR`` | ``flow_dissector`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_KPROBE`` | | ``kprobe+`` [#kprobe]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``kretprobe+`` [#kprobe]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``ksyscall+`` [#ksyscall]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``kretsyscall+`` [#ksyscall]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``uprobe+`` [#uprobe]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``uprobe.s+`` [#uprobe]_ | Yes |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``uretprobe+`` [#uprobe]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``uretprobe.s+`` [#uprobe]_ | Yes |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``usdt+`` [#usdt]_ | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TRACE_KPROBE_MULTI`` | ``kprobe.multi+`` [#kpmulti]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``kretprobe.multi+`` [#kpmulti]_ | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LIRC_MODE2`` | ``BPF_LIRC_MODE2`` | ``lirc_mode2`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LSM`` | ``BPF_LSM_CGROUP`` | ``lsm_cgroup+`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_LSM_MAC`` | ``lsm+`` [#lsm]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``lsm.s+`` [#lsm]_ | Yes |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LWT_IN`` | | ``lwt_in`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LWT_OUT`` | | ``lwt_out`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LWT_SEG6LOCAL`` | | ``lwt_seg6local`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_LWT_XMIT`` | | ``lwt_xmit`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_NETFILTER`` | | ``netfilter`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_PERF_EVENT`` | | ``perf_event`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE`` | | ``raw_tp.w+`` [#rawtp]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``raw_tracepoint.w+`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_RAW_TRACEPOINT`` | | ``raw_tp+`` [#rawtp]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``raw_tracepoint+`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SCHED_ACT`` | | ``action`` [#tc_legacy]_ | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SCHED_CLS`` | | ``classifier`` [#tc_legacy]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``tc`` [#tc_legacy]_ | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_NETKIT_PRIMARY`` | ``netkit/primary`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_NETKIT_PEER`` | ``netkit/peer`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TCX_INGRESS`` | ``tc/ingress`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TCX_EGRESS`` | ``tc/egress`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TCX_INGRESS`` | ``tcx/ingress`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TCX_EGRESS`` | ``tcx/egress`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SK_LOOKUP`` | ``BPF_SK_LOOKUP`` | ``sk_lookup`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SK_MSG`` | ``BPF_SK_MSG_VERDICT`` | ``sk_msg`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SK_REUSEPORT`` | ``BPF_SK_REUSEPORT_SELECT_OR_MIGRATE`` | ``sk_reuseport/migrate`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_SK_REUSEPORT_SELECT`` | ``sk_reuseport`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SK_SKB`` | | ``sk_skb`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_SK_SKB_STREAM_PARSER`` | ``sk_skb/stream_parser`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_SK_SKB_STREAM_VERDICT`` | ``sk_skb/stream_verdict`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SOCKET_FILTER`` | | ``socket`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SOCK_OPS`` | ``BPF_CGROUP_SOCK_OPS`` | ``sockops`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_STRUCT_OPS`` | | ``struct_ops+`` [#struct_ops]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``struct_ops.s+`` [#struct_ops]_ | Yes |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SYSCALL`` | | ``syscall`` | Yes |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_TRACEPOINT`` | | ``tp+`` [#tp]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``tracepoint+`` [#tp]_ | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_TRACING`` | ``BPF_MODIFY_RETURN`` | ``fmod_ret+`` [#fentry]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``fmod_ret.s+`` [#fentry]_ | Yes |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TRACE_FENTRY`` | ``fentry+`` [#fentry]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``fentry.s+`` [#fentry]_ | Yes |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TRACE_FEXIT`` | ``fexit+`` [#fentry]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``fexit.s+`` [#fentry]_ | Yes |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TRACE_ITER`` | ``iter+`` [#iter]_ | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``iter.s+`` [#iter]_ | Yes |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_TRACE_RAW_TP`` | ``tp_btf+`` [#fentry]_ | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_XDP`` | ``BPF_XDP_CPUMAP`` | ``xdp.frags/cpumap`` | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``xdp/cpumap`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_XDP_DEVMAP`` | ``xdp.frags/devmap`` | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``xdp/devmap`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_XDP`` | ``xdp.frags`` | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``xdp`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#fentry] The ``fentry`` attach format is ``fentry[.s]/<function>``.
|
||||
.. [#kprobe] The ``kprobe`` attach format is ``kprobe/<function>[+<offset>]``. Valid
|
||||
characters for ``function`` are ``a-zA-Z0-9_.`` and ``offset`` must be a valid
|
||||
non-negative integer.
|
||||
.. [#ksyscall] The ``ksyscall`` attach format is ``ksyscall/<syscall>``.
|
||||
.. [#uprobe] The ``uprobe`` attach format is ``uprobe[.s]/<path>:<function>[+<offset>]``.
|
||||
.. [#usdt] The ``usdt`` attach format is ``usdt/<path>:<provider>:<name>``.
|
||||
.. [#kpmulti] The ``kprobe.multi`` attach format is ``kprobe.multi/<pattern>`` where ``pattern``
|
||||
supports ``*`` and ``?`` wildcards. Valid characters for pattern are
|
||||
``a-zA-Z0-9_.*?``.
|
||||
.. [#lsm] The ``lsm`` attachment format is ``lsm[.s]/<hook>``.
|
||||
.. [#rawtp] The ``raw_tp`` attach format is ``raw_tracepoint[.w]/<tracepoint>``.
|
||||
.. [#tc_legacy] The ``tc``, ``classifier`` and ``action`` attach types are deprecated, use
|
||||
``tcx/*`` instead.
|
||||
.. [#struct_ops] The ``struct_ops`` attach format supports ``struct_ops[.s]/<name>`` convention,
|
||||
but ``name`` is ignored and it is recommended to just use plain
|
||||
``SEC("struct_ops[.s]")``. The attachments are defined in a struct initializer
|
||||
that is tagged with ``SEC(".struct_ops[.link]")``.
|
||||
.. [#tp] The ``tracepoint`` attach format is ``tracepoint/<category>/<name>``.
|
||||
.. [#iter] The ``iter`` attach format is ``iter[.s]/<struct-name>``.
|
||||
@@ -1,2 +1 @@
|
||||
breathe
|
||||
sphinx_rtd_theme
|
||||
breathe
|
||||
@@ -37,14 +37,6 @@
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_CALL_REL(DST) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_JMP | BPF_CALL, \
|
||||
.dst_reg = 0, \
|
||||
.src_reg = BPF_PSEUDO_CALL, \
|
||||
.off = 0, \
|
||||
.imm = DST })
|
||||
|
||||
#define BPF_EXIT_INSN() \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_JMP | BPF_EXIT, \
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#ifndef __LINUX_KERNEL_H
|
||||
#define __LINUX_KERNEL_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,8 +36,7 @@ struct btf_type {
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union, enum, fwd, enum64,
|
||||
* decl_tag and type_tag
|
||||
* struct, union, enum, fwd and enum64
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
|
||||
|
||||
@@ -211,9 +211,6 @@ struct rtnl_link_stats {
|
||||
* @rx_nohandler: Number of packets received on the interface
|
||||
* but dropped by the networking stack because the device is
|
||||
* not designated to receive packets (e.g. backup link in a bond).
|
||||
*
|
||||
* @rx_otherhost_dropped: Number of packets dropped due to mismatch
|
||||
* in destination MAC address.
|
||||
*/
|
||||
struct rtnl_link_stats64 {
|
||||
__u64 rx_packets;
|
||||
@@ -246,23 +243,6 @@ struct rtnl_link_stats64 {
|
||||
__u64 rx_compressed;
|
||||
__u64 tx_compressed;
|
||||
__u64 rx_nohandler;
|
||||
|
||||
__u64 rx_otherhost_dropped;
|
||||
};
|
||||
|
||||
/* Subset of link stats useful for in-HW collection. Meaning of the fields is as
|
||||
* for struct rtnl_link_stats64.
|
||||
*/
|
||||
struct rtnl_hw_stats64 {
|
||||
__u64 rx_packets;
|
||||
__u64 tx_packets;
|
||||
__u64 rx_bytes;
|
||||
__u64 tx_bytes;
|
||||
__u64 rx_errors;
|
||||
__u64 tx_errors;
|
||||
__u64 rx_dropped;
|
||||
__u64 tx_dropped;
|
||||
__u64 multicast;
|
||||
};
|
||||
|
||||
/* The struct should be in sync with struct ifmap */
|
||||
@@ -370,14 +350,7 @@ enum {
|
||||
IFLA_GRO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SEGS,
|
||||
IFLA_ALLMULTI, /* Allmulti count: > 0 means acts ALLMULTI */
|
||||
|
||||
IFLA_DEVLINK_PORT,
|
||||
|
||||
IFLA_GSO_IPV4_MAX_SIZE,
|
||||
IFLA_GRO_IPV4_MAX_SIZE,
|
||||
IFLA_DPLL_PIN,
|
||||
IFLA_MAX_PACING_OFFLOAD_HORIZON,
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
@@ -462,286 +435,6 @@ enum in6_addr_gen_mode {
|
||||
|
||||
/* Bridge section */
|
||||
|
||||
/**
|
||||
* DOC: Bridge enum definition
|
||||
*
|
||||
* Please *note* that the timer values in the following section are expected
|
||||
* in clock_t format, which is seconds multiplied by USER_HZ (generally
|
||||
* defined as 100).
|
||||
*
|
||||
* @IFLA_BR_FORWARD_DELAY
|
||||
* The bridge forwarding delay is the time spent in LISTENING state
|
||||
* (before moving to LEARNING) and in LEARNING state (before moving
|
||||
* to FORWARDING). Only relevant if STP is enabled.
|
||||
*
|
||||
* The valid values are between (2 * USER_HZ) and (30 * USER_HZ).
|
||||
* The default value is (15 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_HELLO_TIME
|
||||
* The time between hello packets sent by the bridge, when it is a root
|
||||
* bridge or a designated bridge. Only relevant if STP is enabled.
|
||||
*
|
||||
* The valid values are between (1 * USER_HZ) and (10 * USER_HZ).
|
||||
* The default value is (2 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MAX_AGE
|
||||
* The hello packet timeout is the time until another bridge in the
|
||||
* spanning tree is assumed to be dead, after reception of its last hello
|
||||
* message. Only relevant if STP is enabled.
|
||||
*
|
||||
* The valid values are between (6 * USER_HZ) and (40 * USER_HZ).
|
||||
* The default value is (20 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_AGEING_TIME
|
||||
* Configure the bridge's FDB entries aging time. It is the time a MAC
|
||||
* address will be kept in the FDB after a packet has been received from
|
||||
* that address. After this time has passed, entries are cleaned up.
|
||||
* Allow values outside the 802.1 standard specification for special cases:
|
||||
*
|
||||
* * 0 - entry never ages (all permanent)
|
||||
* * 1 - entry disappears (no persistence)
|
||||
*
|
||||
* The default value is (300 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_STP_STATE
|
||||
* Turn spanning tree protocol on (*IFLA_BR_STP_STATE* > 0) or off
|
||||
* (*IFLA_BR_STP_STATE* == 0) for this bridge.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_PRIORITY
|
||||
* Set this bridge's spanning tree priority, used during STP root bridge
|
||||
* election.
|
||||
*
|
||||
* The valid values are between 0 and 65535.
|
||||
*
|
||||
* @IFLA_BR_VLAN_FILTERING
|
||||
* Turn VLAN filtering on (*IFLA_BR_VLAN_FILTERING* > 0) or off
|
||||
* (*IFLA_BR_VLAN_FILTERING* == 0). When disabled, the bridge will not
|
||||
* consider the VLAN tag when handling packets.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_VLAN_PROTOCOL
|
||||
* Set the protocol used for VLAN filtering.
|
||||
*
|
||||
* The valid values are 0x8100(802.1Q) or 0x88A8(802.1AD). The default value
|
||||
* is 0x8100(802.1Q).
|
||||
*
|
||||
* @IFLA_BR_GROUP_FWD_MASK
|
||||
* The group forwarding mask. This is the bitmask that is applied to
|
||||
* decide whether to forward incoming frames destined to link-local
|
||||
* addresses (of the form 01:80:C2:00:00:0X).
|
||||
*
|
||||
* The default value is 0, which means the bridge does not forward any
|
||||
* link-local frames coming on this port.
|
||||
*
|
||||
* @IFLA_BR_ROOT_ID
|
||||
* The bridge root id, read only.
|
||||
*
|
||||
* @IFLA_BR_BRIDGE_ID
|
||||
* The bridge id, read only.
|
||||
*
|
||||
* @IFLA_BR_ROOT_PORT
|
||||
* The bridge root port, read only.
|
||||
*
|
||||
* @IFLA_BR_ROOT_PATH_COST
|
||||
* The bridge root path cost, read only.
|
||||
*
|
||||
* @IFLA_BR_TOPOLOGY_CHANGE
|
||||
* The bridge topology change, read only.
|
||||
*
|
||||
* @IFLA_BR_TOPOLOGY_CHANGE_DETECTED
|
||||
* The bridge topology change detected, read only.
|
||||
*
|
||||
* @IFLA_BR_HELLO_TIMER
|
||||
* The bridge hello timer, read only.
|
||||
*
|
||||
* @IFLA_BR_TCN_TIMER
|
||||
* The bridge tcn timer, read only.
|
||||
*
|
||||
* @IFLA_BR_TOPOLOGY_CHANGE_TIMER
|
||||
* The bridge topology change timer, read only.
|
||||
*
|
||||
* @IFLA_BR_GC_TIMER
|
||||
* The bridge gc timer, read only.
|
||||
*
|
||||
* @IFLA_BR_GROUP_ADDR
|
||||
* Set the MAC address of the multicast group this bridge uses for STP.
|
||||
* The address must be a link-local address in standard Ethernet MAC address
|
||||
* format. It is an address of the form 01:80:C2:00:00:0X, with X in [0, 4..f].
|
||||
*
|
||||
* The default value is 0.
|
||||
*
|
||||
* @IFLA_BR_FDB_FLUSH
|
||||
* Flush bridge's fdb dynamic entries.
|
||||
*
|
||||
* @IFLA_BR_MCAST_ROUTER
|
||||
* Set bridge's multicast router if IGMP snooping is enabled.
|
||||
* The valid values are:
|
||||
*
|
||||
* * 0 - disabled.
|
||||
* * 1 - automatic (queried).
|
||||
* * 2 - permanently enabled.
|
||||
*
|
||||
* The default value is 1.
|
||||
*
|
||||
* @IFLA_BR_MCAST_SNOOPING
|
||||
* Turn multicast snooping on (*IFLA_BR_MCAST_SNOOPING* > 0) or off
|
||||
* (*IFLA_BR_MCAST_SNOOPING* == 0).
|
||||
*
|
||||
* The default value is 1.
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERY_USE_IFADDR
|
||||
* If enabled use the bridge's own IP address as source address for IGMP
|
||||
* queries (*IFLA_BR_MCAST_QUERY_USE_IFADDR* > 0) or the default of 0.0.0.0
|
||||
* (*IFLA_BR_MCAST_QUERY_USE_IFADDR* == 0).
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERIER
|
||||
* Enable (*IFLA_BR_MULTICAST_QUERIER* > 0) or disable
|
||||
* (*IFLA_BR_MULTICAST_QUERIER* == 0) IGMP querier, ie sending of multicast
|
||||
* queries by the bridge.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_MCAST_HASH_ELASTICITY
|
||||
* Set multicast database hash elasticity, It is the maximum chain length in
|
||||
* the multicast hash table. This attribute is *deprecated* and the value
|
||||
* is always 16.
|
||||
*
|
||||
* @IFLA_BR_MCAST_HASH_MAX
|
||||
* Set maximum size of the multicast hash table
|
||||
*
|
||||
* The default value is 4096, the value must be a power of 2.
|
||||
*
|
||||
* @IFLA_BR_MCAST_LAST_MEMBER_CNT
|
||||
* The Last Member Query Count is the number of Group-Specific Queries
|
||||
* sent before the router assumes there are no local members. The Last
|
||||
* Member Query Count is also the number of Group-and-Source-Specific
|
||||
* Queries sent before the router assumes there are no listeners for a
|
||||
* particular source.
|
||||
*
|
||||
* The default value is 2.
|
||||
*
|
||||
* @IFLA_BR_MCAST_STARTUP_QUERY_CNT
|
||||
* The Startup Query Count is the number of Queries sent out on startup,
|
||||
* separated by the Startup Query Interval.
|
||||
*
|
||||
* The default value is 2.
|
||||
*
|
||||
* @IFLA_BR_MCAST_LAST_MEMBER_INTVL
|
||||
* The Last Member Query Interval is the Max Response Time inserted into
|
||||
* Group-Specific Queries sent in response to Leave Group messages, and
|
||||
* is also the amount of time between Group-Specific Query messages.
|
||||
*
|
||||
* The default value is (1 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MCAST_MEMBERSHIP_INTVL
|
||||
* The interval after which the bridge will leave a group, if no membership
|
||||
* reports for this group are received.
|
||||
*
|
||||
* The default value is (260 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERIER_INTVL
|
||||
* The interval between queries sent by other routers. if no queries are
|
||||
* seen after this delay has passed, the bridge will start to send its own
|
||||
* queries (as if *IFLA_BR_MCAST_QUERIER_INTVL* was enabled).
|
||||
*
|
||||
* The default value is (255 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERY_INTVL
|
||||
* The Query Interval is the interval between General Queries sent by
|
||||
* the Querier.
|
||||
*
|
||||
* The default value is (125 * USER_HZ). The minimum value is (1 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
|
||||
* The Max Response Time used to calculate the Max Resp Code inserted
|
||||
* into the periodic General Queries.
|
||||
*
|
||||
* The default value is (10 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_MCAST_STARTUP_QUERY_INTVL
|
||||
* The interval between queries in the startup phase.
|
||||
*
|
||||
* The default value is (125 * USER_HZ) / 4. The minimum value is (1 * USER_HZ).
|
||||
*
|
||||
* @IFLA_BR_NF_CALL_IPTABLES
|
||||
* Enable (*NF_CALL_IPTABLES* > 0) or disable (*NF_CALL_IPTABLES* == 0)
|
||||
* iptables hooks on the bridge.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_NF_CALL_IP6TABLES
|
||||
* Enable (*NF_CALL_IP6TABLES* > 0) or disable (*NF_CALL_IP6TABLES* == 0)
|
||||
* ip6tables hooks on the bridge.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_NF_CALL_ARPTABLES
|
||||
* Enable (*NF_CALL_ARPTABLES* > 0) or disable (*NF_CALL_ARPTABLES* == 0)
|
||||
* arptables hooks on the bridge.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_VLAN_DEFAULT_PVID
|
||||
* VLAN ID applied to untagged and priority-tagged incoming packets.
|
||||
*
|
||||
* The default value is 1. Setting to the special value 0 makes all ports of
|
||||
* this bridge not have a PVID by default, which means that they will
|
||||
* not accept VLAN-untagged traffic.
|
||||
*
|
||||
* @IFLA_BR_PAD
|
||||
* Bridge attribute padding type for netlink message.
|
||||
*
|
||||
* @IFLA_BR_VLAN_STATS_ENABLED
|
||||
* Enable (*IFLA_BR_VLAN_STATS_ENABLED* == 1) or disable
|
||||
* (*IFLA_BR_VLAN_STATS_ENABLED* == 0) per-VLAN stats accounting.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_MCAST_STATS_ENABLED
|
||||
* Enable (*IFLA_BR_MCAST_STATS_ENABLED* > 0) or disable
|
||||
* (*IFLA_BR_MCAST_STATS_ENABLED* == 0) multicast (IGMP/MLD) stats
|
||||
* accounting.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_MCAST_IGMP_VERSION
|
||||
* Set the IGMP version.
|
||||
*
|
||||
* The valid values are 2 and 3. The default value is 2.
|
||||
*
|
||||
* @IFLA_BR_MCAST_MLD_VERSION
|
||||
* Set the MLD version.
|
||||
*
|
||||
* The valid values are 1 and 2. The default value is 1.
|
||||
*
|
||||
* @IFLA_BR_VLAN_STATS_PER_PORT
|
||||
* Enable (*IFLA_BR_VLAN_STATS_PER_PORT* == 1) or disable
|
||||
* (*IFLA_BR_VLAN_STATS_PER_PORT* == 0) per-VLAN per-port stats accounting.
|
||||
* Can be changed only when there are no port VLANs configured.
|
||||
*
|
||||
* The default value is 0 (disabled).
|
||||
*
|
||||
* @IFLA_BR_MULTI_BOOLOPT
|
||||
* The multi_boolopt is used to control new boolean options to avoid adding
|
||||
* new netlink attributes. You can look at ``enum br_boolopt_id`` for those
|
||||
* options.
|
||||
*
|
||||
* @IFLA_BR_MCAST_QUERIER_STATE
|
||||
* Bridge mcast querier states, read only.
|
||||
*
|
||||
* @IFLA_BR_FDB_N_LEARNED
|
||||
* The number of dynamically learned FDB entries for the current bridge,
|
||||
* read only.
|
||||
*
|
||||
* @IFLA_BR_FDB_MAX_LEARNED
|
||||
* Set the number of max dynamically learned FDB entries for the current
|
||||
* bridge.
|
||||
*/
|
||||
enum {
|
||||
IFLA_BR_UNSPEC,
|
||||
IFLA_BR_FORWARD_DELAY,
|
||||
@@ -791,8 +484,6 @@ enum {
|
||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||
IFLA_BR_MULTI_BOOLOPT,
|
||||
IFLA_BR_MCAST_QUERIER_STATE,
|
||||
IFLA_BR_FDB_N_LEARNED,
|
||||
IFLA_BR_FDB_MAX_LEARNED,
|
||||
__IFLA_BR_MAX,
|
||||
};
|
||||
|
||||
@@ -803,252 +494,11 @@ struct ifla_bridge_id {
|
||||
__u8 addr[6]; /* ETH_ALEN */
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: Bridge mode enum definition
|
||||
*
|
||||
* @BRIDGE_MODE_HAIRPIN
|
||||
* Controls whether traffic may be sent back out of the port on which it
|
||||
* was received. This option is also called reflective relay mode, and is
|
||||
* used to support basic VEPA (Virtual Ethernet Port Aggregator)
|
||||
* capabilities. By default, this flag is turned off and the bridge will
|
||||
* not forward traffic back out of the receiving port.
|
||||
*/
|
||||
enum {
|
||||
BRIDGE_MODE_UNSPEC,
|
||||
BRIDGE_MODE_HAIRPIN,
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: Bridge port enum definition
|
||||
*
|
||||
* @IFLA_BRPORT_STATE
|
||||
* The operation state of the port. Here are the valid values.
|
||||
*
|
||||
* * 0 - port is in STP *DISABLED* state. Make this port completely
|
||||
* inactive for STP. This is also called BPDU filter and could be used
|
||||
* to disable STP on an untrusted port, like a leaf virtual device.
|
||||
* The traffic forwarding is also stopped on this port.
|
||||
* * 1 - port is in STP *LISTENING* state. Only valid if STP is enabled
|
||||
* on the bridge. In this state the port listens for STP BPDUs and
|
||||
* drops all other traffic frames.
|
||||
* * 2 - port is in STP *LEARNING* state. Only valid if STP is enabled on
|
||||
* the bridge. In this state the port will accept traffic only for the
|
||||
* purpose of updating MAC address tables.
|
||||
* * 3 - port is in STP *FORWARDING* state. Port is fully active.
|
||||
* * 4 - port is in STP *BLOCKING* state. Only valid if STP is enabled on
|
||||
* the bridge. This state is used during the STP election process.
|
||||
* In this state, port will only process STP BPDUs.
|
||||
*
|
||||
* @IFLA_BRPORT_PRIORITY
|
||||
* The STP port priority. The valid values are between 0 and 255.
|
||||
*
|
||||
* @IFLA_BRPORT_COST
|
||||
* The STP path cost of the port. The valid values are between 1 and 65535.
|
||||
*
|
||||
* @IFLA_BRPORT_MODE
|
||||
* Set the bridge port mode. See *BRIDGE_MODE_HAIRPIN* for more details.
|
||||
*
|
||||
* @IFLA_BRPORT_GUARD
|
||||
* Controls whether STP BPDUs will be processed by the bridge port. By
|
||||
* default, the flag is turned off to allow BPDU processing. Turning this
|
||||
* flag on will disable the bridge port if a STP BPDU packet is received.
|
||||
*
|
||||
* If the bridge has Spanning Tree enabled, hostile devices on the network
|
||||
* may send BPDU on a port and cause network failure. Setting *guard on*
|
||||
* will detect and stop this by disabling the port. The port will be
|
||||
* restarted if the link is brought down, or removed and reattached.
|
||||
*
|
||||
* @IFLA_BRPORT_PROTECT
|
||||
* Controls whether a given port is allowed to become a root port or not.
|
||||
* Only used when STP is enabled on the bridge. By default the flag is off.
|
||||
*
|
||||
* This feature is also called root port guard. If BPDU is received from a
|
||||
* leaf (edge) port, it should not be elected as root port. This could
|
||||
* be used if using STP on a bridge and the downstream bridges are not fully
|
||||
* trusted; this prevents a hostile guest from rerouting traffic.
|
||||
*
|
||||
* @IFLA_BRPORT_FAST_LEAVE
|
||||
* This flag allows the bridge to immediately stop multicast traffic
|
||||
* forwarding on a port that receives an IGMP Leave message. It is only used
|
||||
* when IGMP snooping is enabled on the bridge. By default the flag is off.
|
||||
*
|
||||
* @IFLA_BRPORT_LEARNING
|
||||
* Controls whether a given port will learn *source* MAC addresses from
|
||||
* received traffic or not. Also controls whether dynamic FDB entries
|
||||
* (which can also be added by software) will be refreshed by incoming
|
||||
* traffic. By default this flag is on.
|
||||
*
|
||||
* @IFLA_BRPORT_UNICAST_FLOOD
|
||||
* Controls whether unicast traffic for which there is no FDB entry will
|
||||
* be flooded towards this port. By default this flag is on.
|
||||
*
|
||||
* @IFLA_BRPORT_PROXYARP
|
||||
* Enable proxy ARP on this port.
|
||||
*
|
||||
* @IFLA_BRPORT_LEARNING_SYNC
|
||||
* Controls whether a given port will sync MAC addresses learned on device
|
||||
* port to bridge FDB.
|
||||
*
|
||||
* @IFLA_BRPORT_PROXYARP_WIFI
|
||||
* Enable proxy ARP on this port which meets extended requirements by
|
||||
* IEEE 802.11 and Hotspot 2.0 specifications.
|
||||
*
|
||||
* @IFLA_BRPORT_ROOT_ID
|
||||
*
|
||||
* @IFLA_BRPORT_BRIDGE_ID
|
||||
*
|
||||
* @IFLA_BRPORT_DESIGNATED_PORT
|
||||
*
|
||||
* @IFLA_BRPORT_DESIGNATED_COST
|
||||
*
|
||||
* @IFLA_BRPORT_ID
|
||||
*
|
||||
* @IFLA_BRPORT_NO
|
||||
*
|
||||
* @IFLA_BRPORT_TOPOLOGY_CHANGE_ACK
|
||||
*
|
||||
* @IFLA_BRPORT_CONFIG_PENDING
|
||||
*
|
||||
* @IFLA_BRPORT_MESSAGE_AGE_TIMER
|
||||
*
|
||||
* @IFLA_BRPORT_FORWARD_DELAY_TIMER
|
||||
*
|
||||
* @IFLA_BRPORT_HOLD_TIMER
|
||||
*
|
||||
* @IFLA_BRPORT_FLUSH
|
||||
* Flush bridge ports' fdb dynamic entries.
|
||||
*
|
||||
* @IFLA_BRPORT_MULTICAST_ROUTER
|
||||
* Configure the port's multicast router presence. A port with
|
||||
* a multicast router will receive all multicast traffic.
|
||||
* The valid values are:
|
||||
*
|
||||
* * 0 disable multicast routers on this port
|
||||
* * 1 let the system detect the presence of routers (default)
|
||||
* * 2 permanently enable multicast traffic forwarding on this port
|
||||
* * 3 enable multicast routers temporarily on this port, not depending
|
||||
* on incoming queries.
|
||||
*
|
||||
* @IFLA_BRPORT_PAD
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_FLOOD
|
||||
* Controls whether a given port will flood multicast traffic for which
|
||||
* there is no MDB entry. By default this flag is on.
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_TO_UCAST
|
||||
* Controls whether a given port will replicate packets using unicast
|
||||
* instead of multicast. By default this flag is off.
|
||||
*
|
||||
* This is done by copying the packet per host and changing the multicast
|
||||
* destination MAC to a unicast one accordingly.
|
||||
*
|
||||
* *mcast_to_unicast* works on top of the multicast snooping feature of the
|
||||
* bridge. Which means unicast copies are only delivered to hosts which
|
||||
* are interested in unicast and signaled this via IGMP/MLD reports previously.
|
||||
*
|
||||
* This feature is intended for interface types which have a more reliable
|
||||
* and/or efficient way to deliver unicast packets than broadcast ones
|
||||
* (e.g. WiFi).
|
||||
*
|
||||
* However, it should only be enabled on interfaces where no IGMPv2/MLDv1
|
||||
* report suppression takes place. IGMP/MLD report suppression issue is
|
||||
* usually overcome by the network daemon (supplicant) enabling AP isolation
|
||||
* and by that separating all STAs.
|
||||
*
|
||||
* Delivery of STA-to-STA IP multicast is made possible again by enabling
|
||||
* and utilizing the bridge hairpin mode, which considers the incoming port
|
||||
* as a potential outgoing port, too (see *BRIDGE_MODE_HAIRPIN* option).
|
||||
* Hairpin mode is performed after multicast snooping, therefore leading
|
||||
* to only deliver reports to STAs running a multicast router.
|
||||
*
|
||||
* @IFLA_BRPORT_VLAN_TUNNEL
|
||||
* Controls whether vlan to tunnel mapping is enabled on the port.
|
||||
* By default this flag is off.
|
||||
*
|
||||
* @IFLA_BRPORT_BCAST_FLOOD
|
||||
* Controls flooding of broadcast traffic on the given port. By default
|
||||
* this flag is on.
|
||||
*
|
||||
* @IFLA_BRPORT_GROUP_FWD_MASK
|
||||
* Set the group forward mask. This is a bitmask that is applied to
|
||||
* decide whether to forward incoming frames destined to link-local
|
||||
* addresses. The addresses of the form are 01:80:C2:00:00:0X (defaults
|
||||
* to 0, which means the bridge does not forward any link-local frames
|
||||
* coming on this port).
|
||||
*
|
||||
* @IFLA_BRPORT_NEIGH_SUPPRESS
|
||||
* Controls whether neighbor discovery (arp and nd) proxy and suppression
|
||||
* is enabled on the port. By default this flag is off.
|
||||
*
|
||||
* @IFLA_BRPORT_ISOLATED
|
||||
* Controls whether a given port will be isolated, which means it will be
|
||||
* able to communicate with non-isolated ports only. By default this
|
||||
* flag is off.
|
||||
*
|
||||
* @IFLA_BRPORT_BACKUP_PORT
|
||||
* Set a backup port. If the port loses carrier all traffic will be
|
||||
* redirected to the configured backup port. Set the value to 0 to disable
|
||||
* it.
|
||||
*
|
||||
* @IFLA_BRPORT_MRP_RING_OPEN
|
||||
*
|
||||
* @IFLA_BRPORT_MRP_IN_OPEN
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT
|
||||
* The number of per-port EHT hosts limit. The default value is 512.
|
||||
* Setting to 0 is not allowed.
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_EHT_HOSTS_CNT
|
||||
* The current number of tracked hosts, read only.
|
||||
*
|
||||
* @IFLA_BRPORT_LOCKED
|
||||
* Controls whether a port will be locked, meaning that hosts behind the
|
||||
* port will not be able to communicate through the port unless an FDB
|
||||
* entry with the unit's MAC address is in the FDB. The common use case is
|
||||
* that hosts are allowed access through authentication with the IEEE 802.1X
|
||||
* protocol or based on whitelists. By default this flag is off.
|
||||
*
|
||||
* Please note that secure 802.1X deployments should always use the
|
||||
* *BR_BOOLOPT_NO_LL_LEARN* flag, to not permit the bridge to populate its
|
||||
* FDB based on link-local (EAPOL) traffic received on the port.
|
||||
*
|
||||
* @IFLA_BRPORT_MAB
|
||||
* Controls whether a port will use MAC Authentication Bypass (MAB), a
|
||||
* technique through which select MAC addresses may be allowed on a locked
|
||||
* port, without using 802.1X authentication. Packets with an unknown source
|
||||
* MAC address generates a "locked" FDB entry on the incoming bridge port.
|
||||
* The common use case is for user space to react to these bridge FDB
|
||||
* notifications and optionally replace the locked FDB entry with a normal
|
||||
* one, allowing traffic to pass for whitelisted MAC addresses.
|
||||
*
|
||||
* Setting this flag also requires *IFLA_BRPORT_LOCKED* and
|
||||
* *IFLA_BRPORT_LEARNING*. *IFLA_BRPORT_LOCKED* ensures that unauthorized
|
||||
* data packets are dropped, and *IFLA_BRPORT_LEARNING* allows the dynamic
|
||||
* FDB entries installed by user space (as replacements for the locked FDB
|
||||
* entries) to be refreshed and/or aged out.
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_N_GROUPS
|
||||
*
|
||||
* @IFLA_BRPORT_MCAST_MAX_GROUPS
|
||||
* Sets the maximum number of MDB entries that can be registered for a
|
||||
* given port. Attempts to register more MDB entries at the port than this
|
||||
* limit allows will be rejected, whether they are done through netlink
|
||||
* (e.g. the bridge tool), or IGMP or MLD membership reports. Setting a
|
||||
* limit of 0 disables the limit. The default value is 0.
|
||||
*
|
||||
* @IFLA_BRPORT_NEIGH_VLAN_SUPPRESS
|
||||
* Controls whether neighbor discovery (arp and nd) proxy and suppression is
|
||||
* enabled for a given port. By default this flag is off.
|
||||
*
|
||||
* Note that this option only takes effect when *IFLA_BRPORT_NEIGH_SUPPRESS*
|
||||
* is enabled for a given port.
|
||||
*
|
||||
* @IFLA_BRPORT_BACKUP_NHID
|
||||
* The FDB nexthop object ID to attach to packets being redirected to a
|
||||
* backup port that has VLAN tunnel mapping enabled (via the
|
||||
* *IFLA_BRPORT_VLAN_TUNNEL* option). Setting a value of 0 (default) has
|
||||
* the effect of not attaching any ID.
|
||||
*/
|
||||
enum {
|
||||
IFLA_BRPORT_UNSPEC,
|
||||
IFLA_BRPORT_STATE, /* Spanning tree state */
|
||||
@@ -1089,12 +539,6 @@ enum {
|
||||
IFLA_BRPORT_MRP_IN_OPEN,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
|
||||
IFLA_BRPORT_LOCKED,
|
||||
IFLA_BRPORT_MAB,
|
||||
IFLA_BRPORT_MCAST_N_GROUPS,
|
||||
IFLA_BRPORT_MCAST_MAX_GROUPS,
|
||||
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
|
||||
IFLA_BRPORT_BACKUP_NHID,
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
@@ -1161,7 +605,6 @@ enum {
|
||||
IFLA_MACVLAN_MACADDR_COUNT,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
|
||||
IFLA_MACVLAN_BC_CUTOFF,
|
||||
__IFLA_MACVLAN_MAX,
|
||||
};
|
||||
|
||||
@@ -1230,7 +673,6 @@ enum {
|
||||
IFLA_XFRM_UNSPEC,
|
||||
IFLA_XFRM_LINK,
|
||||
IFLA_XFRM_IF_ID,
|
||||
IFLA_XFRM_COLLECT_METADATA,
|
||||
__IFLA_XFRM_MAX
|
||||
};
|
||||
|
||||
@@ -1272,96 +714,7 @@ enum ipvlan_mode {
|
||||
#define IPVLAN_F_PRIVATE 0x01
|
||||
#define IPVLAN_F_VEPA 0x02
|
||||
|
||||
/* Tunnel RTM header */
|
||||
struct tunnel_msg {
|
||||
__u8 family;
|
||||
__u8 flags;
|
||||
__u16 reserved2;
|
||||
__u32 ifindex;
|
||||
};
|
||||
|
||||
/* netkit section */
|
||||
enum netkit_action {
|
||||
NETKIT_NEXT = -1,
|
||||
NETKIT_PASS = 0,
|
||||
NETKIT_DROP = 2,
|
||||
NETKIT_REDIRECT = 7,
|
||||
};
|
||||
|
||||
enum netkit_mode {
|
||||
NETKIT_L2,
|
||||
NETKIT_L3,
|
||||
};
|
||||
|
||||
/* NETKIT_SCRUB_NONE leaves clearing skb->{mark,priority} up to
|
||||
* the BPF program if attached. This also means the latter can
|
||||
* consume the two fields if they were populated earlier.
|
||||
*
|
||||
* NETKIT_SCRUB_DEFAULT zeroes skb->{mark,priority} fields before
|
||||
* invoking the attached BPF program when the peer device resides
|
||||
* in a different network namespace. This is the default behavior.
|
||||
*/
|
||||
enum netkit_scrub {
|
||||
NETKIT_SCRUB_NONE,
|
||||
NETKIT_SCRUB_DEFAULT,
|
||||
};
|
||||
|
||||
enum {
|
||||
IFLA_NETKIT_UNSPEC,
|
||||
IFLA_NETKIT_PEER_INFO,
|
||||
IFLA_NETKIT_PRIMARY,
|
||||
IFLA_NETKIT_POLICY,
|
||||
IFLA_NETKIT_PEER_POLICY,
|
||||
IFLA_NETKIT_MODE,
|
||||
IFLA_NETKIT_SCRUB,
|
||||
IFLA_NETKIT_PEER_SCRUB,
|
||||
IFLA_NETKIT_HEADROOM,
|
||||
IFLA_NETKIT_TAILROOM,
|
||||
__IFLA_NETKIT_MAX,
|
||||
};
|
||||
#define IFLA_NETKIT_MAX (__IFLA_NETKIT_MAX - 1)
|
||||
|
||||
/* VXLAN section */
|
||||
|
||||
/* include statistics in the dump */
|
||||
#define TUNNEL_MSG_FLAG_STATS 0x01
|
||||
|
||||
#define TUNNEL_MSG_VALID_USER_FLAGS TUNNEL_MSG_FLAG_STATS
|
||||
|
||||
/* Embedded inside VXLAN_VNIFILTER_ENTRY_STATS */
|
||||
enum {
|
||||
VNIFILTER_ENTRY_STATS_UNSPEC,
|
||||
VNIFILTER_ENTRY_STATS_RX_BYTES,
|
||||
VNIFILTER_ENTRY_STATS_RX_PKTS,
|
||||
VNIFILTER_ENTRY_STATS_RX_DROPS,
|
||||
VNIFILTER_ENTRY_STATS_RX_ERRORS,
|
||||
VNIFILTER_ENTRY_STATS_TX_BYTES,
|
||||
VNIFILTER_ENTRY_STATS_TX_PKTS,
|
||||
VNIFILTER_ENTRY_STATS_TX_DROPS,
|
||||
VNIFILTER_ENTRY_STATS_TX_ERRORS,
|
||||
VNIFILTER_ENTRY_STATS_PAD,
|
||||
__VNIFILTER_ENTRY_STATS_MAX
|
||||
};
|
||||
#define VNIFILTER_ENTRY_STATS_MAX (__VNIFILTER_ENTRY_STATS_MAX - 1)
|
||||
|
||||
enum {
|
||||
VXLAN_VNIFILTER_ENTRY_UNSPEC,
|
||||
VXLAN_VNIFILTER_ENTRY_START,
|
||||
VXLAN_VNIFILTER_ENTRY_END,
|
||||
VXLAN_VNIFILTER_ENTRY_GROUP,
|
||||
VXLAN_VNIFILTER_ENTRY_GROUP6,
|
||||
VXLAN_VNIFILTER_ENTRY_STATS,
|
||||
__VXLAN_VNIFILTER_ENTRY_MAX
|
||||
};
|
||||
#define VXLAN_VNIFILTER_ENTRY_MAX (__VXLAN_VNIFILTER_ENTRY_MAX - 1)
|
||||
|
||||
enum {
|
||||
VXLAN_VNIFILTER_UNSPEC,
|
||||
VXLAN_VNIFILTER_ENTRY,
|
||||
__VXLAN_VNIFILTER_MAX
|
||||
};
|
||||
#define VXLAN_VNIFILTER_MAX (__VXLAN_VNIFILTER_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_VXLAN_UNSPEC,
|
||||
IFLA_VXLAN_ID,
|
||||
@@ -1393,9 +746,6 @@ enum {
|
||||
IFLA_VXLAN_GPE,
|
||||
IFLA_VXLAN_TTL_INHERIT,
|
||||
IFLA_VXLAN_DF,
|
||||
IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */
|
||||
IFLA_VXLAN_LOCALBYPASS,
|
||||
IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */
|
||||
__IFLA_VXLAN_MAX
|
||||
};
|
||||
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
|
||||
@@ -1413,13 +763,6 @@ enum ifla_vxlan_df {
|
||||
VXLAN_DF_MAX = __VXLAN_DF_END - 1,
|
||||
};
|
||||
|
||||
enum ifla_vxlan_label_policy {
|
||||
VXLAN_LABEL_FIXED = 0,
|
||||
VXLAN_LABEL_INHERIT = 1,
|
||||
__VXLAN_LABEL_END,
|
||||
VXLAN_LABEL_MAX = __VXLAN_LABEL_END - 1,
|
||||
};
|
||||
|
||||
/* GENEVE section */
|
||||
enum {
|
||||
IFLA_GENEVE_UNSPEC,
|
||||
@@ -1436,7 +779,6 @@ enum {
|
||||
IFLA_GENEVE_LABEL,
|
||||
IFLA_GENEVE_TTL_INHERIT,
|
||||
IFLA_GENEVE_DF,
|
||||
IFLA_GENEVE_INNER_PROTO_INHERIT,
|
||||
__IFLA_GENEVE_MAX
|
||||
};
|
||||
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
|
||||
@@ -1482,10 +824,6 @@ enum {
|
||||
IFLA_GTP_FD1,
|
||||
IFLA_GTP_PDP_HASHSIZE,
|
||||
IFLA_GTP_ROLE,
|
||||
IFLA_GTP_CREATE_SOCKETS,
|
||||
IFLA_GTP_RESTART_COUNT,
|
||||
IFLA_GTP_LOCAL,
|
||||
IFLA_GTP_LOCAL6,
|
||||
__IFLA_GTP_MAX,
|
||||
};
|
||||
#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
|
||||
@@ -1525,7 +863,6 @@ enum {
|
||||
IFLA_BOND_AD_LACP_ACTIVE,
|
||||
IFLA_BOND_MISSED_MAX,
|
||||
IFLA_BOND_NS_IP6_TARGET,
|
||||
IFLA_BOND_COUPLED_CONTROL,
|
||||
__IFLA_BOND_MAX,
|
||||
};
|
||||
|
||||
@@ -1791,7 +1128,6 @@ enum {
|
||||
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
|
||||
* HSR. For example PRP.
|
||||
*/
|
||||
IFLA_HSR_INTERLINK, /* HSR interlink network device */
|
||||
__IFLA_HSR_MAX,
|
||||
};
|
||||
|
||||
@@ -1824,17 +1160,6 @@ enum {
|
||||
|
||||
#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1))
|
||||
|
||||
enum {
|
||||
IFLA_STATS_GETSET_UNSPEC,
|
||||
IFLA_STATS_GET_FILTERS, /* Nest of IFLA_STATS_LINK_xxx, each a u32 with
|
||||
* a filter mask for the corresponding group.
|
||||
*/
|
||||
IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS, /* 0 or 1 as u8 */
|
||||
__IFLA_STATS_GETSET_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_STATS_GETSET_MAX (__IFLA_STATS_GETSET_MAX - 1)
|
||||
|
||||
/* These are embedded into IFLA_STATS_LINK_XSTATS:
|
||||
* [IFLA_STATS_LINK_XSTATS]
|
||||
* -> [LINK_XSTATS_TYPE_xxx]
|
||||
@@ -1852,21 +1177,10 @@ enum {
|
||||
enum {
|
||||
IFLA_OFFLOAD_XSTATS_UNSPEC,
|
||||
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
|
||||
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
|
||||
__IFLA_OFFLOAD_XSTATS_MAX
|
||||
};
|
||||
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC,
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, /* u8 */
|
||||
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, /* u8 */
|
||||
__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX,
|
||||
};
|
||||
#define IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX \
|
||||
(__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX - 1)
|
||||
|
||||
/* XDP section */
|
||||
|
||||
#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
|
||||
@@ -1965,16 +1279,4 @@ enum {
|
||||
|
||||
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
|
||||
|
||||
/* DSA section */
|
||||
|
||||
enum {
|
||||
IFLA_DSA_UNSPEC,
|
||||
IFLA_DSA_CONDUIT,
|
||||
/* Deprecated, use IFLA_DSA_CONDUIT instead */
|
||||
IFLA_DSA_MASTER = IFLA_DSA_CONDUIT,
|
||||
__IFLA_DSA_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_DSA_MAX (__IFLA_DSA_MAX - 1)
|
||||
|
||||
#endif /* _UAPI_LINUX_IF_LINK_H */
|
||||
|
||||
@@ -25,25 +25,9 @@
|
||||
* application.
|
||||
*/
|
||||
#define XDP_USE_NEED_WAKEUP (1 << 3)
|
||||
/* By setting this option, userspace application indicates that it can
|
||||
* handle multiple descriptors per packet thus enabling AF_XDP to split
|
||||
* multi-buffer XDP frames into multiple Rx descriptors. Without this set
|
||||
* such frames will be dropped.
|
||||
*/
|
||||
#define XDP_USE_SG (1 << 4)
|
||||
|
||||
/* Flags for xsk_umem_config flags */
|
||||
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||
|
||||
/* Force checksum calculation in software. Can be used for testing or
|
||||
* working around potential HW issues. This option causes performance
|
||||
* degradation and only works in XDP_COPY mode.
|
||||
*/
|
||||
#define XDP_UMEM_TX_SW_CSUM (1 << 1)
|
||||
|
||||
/* Request to reserve tx_metadata_len bytes of per-chunk metadata.
|
||||
*/
|
||||
#define XDP_UMEM_TX_METADATA_LEN (1 << 2)
|
||||
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||
|
||||
struct sockaddr_xdp {
|
||||
__u16 sxdp_family;
|
||||
@@ -86,7 +70,6 @@ struct xdp_umem_reg {
|
||||
__u32 chunk_size;
|
||||
__u32 headroom;
|
||||
__u32 flags;
|
||||
__u32 tx_metadata_len;
|
||||
};
|
||||
|
||||
struct xdp_statistics {
|
||||
@@ -116,51 +99,6 @@ struct xdp_options {
|
||||
#define XSK_UNALIGNED_BUF_ADDR_MASK \
|
||||
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||
|
||||
/* Request transmit timestamp. Upon completion, put it into tx_timestamp
|
||||
* field of struct xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0)
|
||||
|
||||
/* Request transmit checksum offload. Checksum start position and offset
|
||||
* are communicated via csum_start and csum_offset fields of struct
|
||||
* xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_CHECKSUM (1 << 1)
|
||||
|
||||
/* Request launch time hardware offload. The device will schedule the packet for
|
||||
* transmission at a pre-determined time called launch time. The value of
|
||||
* launch time is communicated via launch_time field of struct xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_LAUNCH_TIME (1 << 2)
|
||||
|
||||
/* AF_XDP offloads request. 'request' union member is consumed by the driver
|
||||
* when the packet is being transmitted. 'completion' union member is
|
||||
* filled by the driver when the transmit completion arrives.
|
||||
*/
|
||||
struct xsk_tx_metadata {
|
||||
__u64 flags;
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* XDP_TXMD_FLAGS_CHECKSUM */
|
||||
|
||||
/* Offset from desc->addr where checksumming should start. */
|
||||
__u16 csum_start;
|
||||
/* Offset from csum_start where checksum should be stored. */
|
||||
__u16 csum_offset;
|
||||
|
||||
/* XDP_TXMD_FLAGS_LAUNCH_TIME */
|
||||
/* Launch time in nanosecond against the PTP HW Clock */
|
||||
__u64 launch_time;
|
||||
} request;
|
||||
|
||||
struct {
|
||||
/* XDP_TXMD_FLAGS_TIMESTAMP */
|
||||
__u64 tx_timestamp;
|
||||
} completion;
|
||||
};
|
||||
};
|
||||
|
||||
/* Rx/Tx descriptor */
|
||||
struct xdp_desc {
|
||||
__u64 addr;
|
||||
@@ -170,14 +108,4 @@ struct xdp_desc {
|
||||
|
||||
/* UMEM descriptor is __u64 */
|
||||
|
||||
/* Flag indicating that the packet continues with the buffer pointed out by the
|
||||
* next frame in the ring. The end of the packet is signalled by setting this
|
||||
* bit to zero. For single buffer packets, every descriptor has 'options' set
|
||||
* to 0 and this maintains backward compatibility.
|
||||
*/
|
||||
#define XDP_PKT_CONTD (1 << 0)
|
||||
|
||||
/* TX packet carries valid metadata. */
|
||||
#define XDP_TX_METADATA (1 << 1)
|
||||
|
||||
#endif /* _LINUX_IF_XDP_H */
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/netdev.yaml */
|
||||
/* YNL-GEN uapi header */
|
||||
|
||||
#ifndef _UAPI_LINUX_NETDEV_H
|
||||
#define _UAPI_LINUX_NETDEV_H
|
||||
|
||||
#define NETDEV_FAMILY_NAME "netdev"
|
||||
#define NETDEV_FAMILY_VERSION 1
|
||||
|
||||
/**
|
||||
* enum netdev_xdp_act
|
||||
* @NETDEV_XDP_ACT_BASIC: XDP features set supported by all drivers
|
||||
* (XDP_ABORTED, XDP_DROP, XDP_PASS, XDP_TX)
|
||||
* @NETDEV_XDP_ACT_REDIRECT: The netdev supports XDP_REDIRECT
|
||||
* @NETDEV_XDP_ACT_NDO_XMIT: This feature informs if netdev implements
|
||||
* ndo_xdp_xmit callback.
|
||||
* @NETDEV_XDP_ACT_XSK_ZEROCOPY: This feature informs if netdev supports AF_XDP
|
||||
* in zero copy mode.
|
||||
* @NETDEV_XDP_ACT_HW_OFFLOAD: This feature informs if netdev supports XDP hw
|
||||
* offloading.
|
||||
* @NETDEV_XDP_ACT_RX_SG: This feature informs if netdev implements non-linear
|
||||
* XDP buffer support in the driver napi callback.
|
||||
* @NETDEV_XDP_ACT_NDO_XMIT_SG: This feature informs if netdev implements
|
||||
* non-linear XDP buffer support in ndo_xdp_xmit callback.
|
||||
*/
|
||||
enum netdev_xdp_act {
|
||||
NETDEV_XDP_ACT_BASIC = 1,
|
||||
NETDEV_XDP_ACT_REDIRECT = 2,
|
||||
NETDEV_XDP_ACT_NDO_XMIT = 4,
|
||||
NETDEV_XDP_ACT_XSK_ZEROCOPY = 8,
|
||||
NETDEV_XDP_ACT_HW_OFFLOAD = 16,
|
||||
NETDEV_XDP_ACT_RX_SG = 32,
|
||||
NETDEV_XDP_ACT_NDO_XMIT_SG = 64,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XDP_ACT_MASK = 127,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netdev_xdp_rx_metadata
|
||||
* @NETDEV_XDP_RX_METADATA_TIMESTAMP: Device is capable of exposing receive HW
|
||||
* timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
* @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet
|
||||
* hash via bpf_xdp_metadata_rx_hash().
|
||||
* @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
|
||||
* packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
|
||||
*/
|
||||
enum netdev_xdp_rx_metadata {
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
|
||||
NETDEV_XDP_RX_METADATA_HASH = 2,
|
||||
NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netdev_xsk_flags
|
||||
* @NETDEV_XSK_FLAGS_TX_TIMESTAMP: HW timestamping egress packets is supported
|
||||
* by the driver.
|
||||
* @NETDEV_XSK_FLAGS_TX_CHECKSUM: L3 checksum HW offload is supported by the
|
||||
* driver.
|
||||
* @NETDEV_XSK_FLAGS_TX_LAUNCH_TIME_FIFO: Launch time HW offload is supported
|
||||
* by the driver.
|
||||
*/
|
||||
enum netdev_xsk_flags {
|
||||
NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1,
|
||||
NETDEV_XSK_FLAGS_TX_CHECKSUM = 2,
|
||||
NETDEV_XSK_FLAGS_TX_LAUNCH_TIME_FIFO = 4,
|
||||
};
|
||||
|
||||
enum netdev_queue_type {
|
||||
NETDEV_QUEUE_TYPE_RX,
|
||||
NETDEV_QUEUE_TYPE_TX,
|
||||
};
|
||||
|
||||
enum netdev_qstats_scope {
|
||||
NETDEV_QSTATS_SCOPE_QUEUE = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_DEV_IFINDEX = 1,
|
||||
NETDEV_A_DEV_PAD,
|
||||
NETDEV_A_DEV_XDP_FEATURES,
|
||||
NETDEV_A_DEV_XDP_ZC_MAX_SEGS,
|
||||
NETDEV_A_DEV_XDP_RX_METADATA_FEATURES,
|
||||
NETDEV_A_DEV_XSK_FEATURES,
|
||||
|
||||
__NETDEV_A_DEV_MAX,
|
||||
NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
__NETDEV_A_IO_URING_PROVIDER_INFO_MAX,
|
||||
NETDEV_A_IO_URING_PROVIDER_INFO_MAX = (__NETDEV_A_IO_URING_PROVIDER_INFO_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_PAGE_POOL_ID = 1,
|
||||
NETDEV_A_PAGE_POOL_IFINDEX,
|
||||
NETDEV_A_PAGE_POOL_NAPI_ID,
|
||||
NETDEV_A_PAGE_POOL_INFLIGHT,
|
||||
NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
|
||||
NETDEV_A_PAGE_POOL_DETACH_TIME,
|
||||
NETDEV_A_PAGE_POOL_DMABUF,
|
||||
NETDEV_A_PAGE_POOL_IO_URING,
|
||||
|
||||
__NETDEV_A_PAGE_POOL_MAX,
|
||||
NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_PAGE_POOL_STATS_INFO = 1,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
|
||||
NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
|
||||
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
|
||||
|
||||
__NETDEV_A_PAGE_POOL_STATS_MAX,
|
||||
NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_NAPI_IFINDEX = 1,
|
||||
NETDEV_A_NAPI_ID,
|
||||
NETDEV_A_NAPI_IRQ,
|
||||
NETDEV_A_NAPI_PID,
|
||||
NETDEV_A_NAPI_DEFER_HARD_IRQS,
|
||||
NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT,
|
||||
NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT,
|
||||
|
||||
__NETDEV_A_NAPI_MAX,
|
||||
NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
__NETDEV_A_XSK_INFO_MAX,
|
||||
NETDEV_A_XSK_INFO_MAX = (__NETDEV_A_XSK_INFO_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_QUEUE_ID = 1,
|
||||
NETDEV_A_QUEUE_IFINDEX,
|
||||
NETDEV_A_QUEUE_TYPE,
|
||||
NETDEV_A_QUEUE_NAPI_ID,
|
||||
NETDEV_A_QUEUE_DMABUF,
|
||||
NETDEV_A_QUEUE_IO_URING,
|
||||
NETDEV_A_QUEUE_XSK,
|
||||
|
||||
__NETDEV_A_QUEUE_MAX,
|
||||
NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_QSTATS_IFINDEX = 1,
|
||||
NETDEV_A_QSTATS_QUEUE_TYPE,
|
||||
NETDEV_A_QSTATS_QUEUE_ID,
|
||||
NETDEV_A_QSTATS_SCOPE,
|
||||
NETDEV_A_QSTATS_RX_PACKETS = 8,
|
||||
NETDEV_A_QSTATS_RX_BYTES,
|
||||
NETDEV_A_QSTATS_TX_PACKETS,
|
||||
NETDEV_A_QSTATS_TX_BYTES,
|
||||
NETDEV_A_QSTATS_RX_ALLOC_FAIL,
|
||||
NETDEV_A_QSTATS_RX_HW_DROPS,
|
||||
NETDEV_A_QSTATS_RX_HW_DROP_OVERRUNS,
|
||||
NETDEV_A_QSTATS_RX_CSUM_COMPLETE,
|
||||
NETDEV_A_QSTATS_RX_CSUM_UNNECESSARY,
|
||||
NETDEV_A_QSTATS_RX_CSUM_NONE,
|
||||
NETDEV_A_QSTATS_RX_CSUM_BAD,
|
||||
NETDEV_A_QSTATS_RX_HW_GRO_PACKETS,
|
||||
NETDEV_A_QSTATS_RX_HW_GRO_BYTES,
|
||||
NETDEV_A_QSTATS_RX_HW_GRO_WIRE_PACKETS,
|
||||
NETDEV_A_QSTATS_RX_HW_GRO_WIRE_BYTES,
|
||||
NETDEV_A_QSTATS_RX_HW_DROP_RATELIMITS,
|
||||
NETDEV_A_QSTATS_TX_HW_DROPS,
|
||||
NETDEV_A_QSTATS_TX_HW_DROP_ERRORS,
|
||||
NETDEV_A_QSTATS_TX_CSUM_NONE,
|
||||
NETDEV_A_QSTATS_TX_NEEDS_CSUM,
|
||||
NETDEV_A_QSTATS_TX_HW_GSO_PACKETS,
|
||||
NETDEV_A_QSTATS_TX_HW_GSO_BYTES,
|
||||
NETDEV_A_QSTATS_TX_HW_GSO_WIRE_PACKETS,
|
||||
NETDEV_A_QSTATS_TX_HW_GSO_WIRE_BYTES,
|
||||
NETDEV_A_QSTATS_TX_HW_DROP_RATELIMITS,
|
||||
NETDEV_A_QSTATS_TX_STOP,
|
||||
NETDEV_A_QSTATS_TX_WAKE,
|
||||
|
||||
__NETDEV_A_QSTATS_MAX,
|
||||
NETDEV_A_QSTATS_MAX = (__NETDEV_A_QSTATS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_DMABUF_IFINDEX = 1,
|
||||
NETDEV_A_DMABUF_QUEUES,
|
||||
NETDEV_A_DMABUF_FD,
|
||||
NETDEV_A_DMABUF_ID,
|
||||
|
||||
__NETDEV_A_DMABUF_MAX,
|
||||
NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_CMD_DEV_GET = 1,
|
||||
NETDEV_CMD_DEV_ADD_NTF,
|
||||
NETDEV_CMD_DEV_DEL_NTF,
|
||||
NETDEV_CMD_DEV_CHANGE_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_GET,
|
||||
NETDEV_CMD_PAGE_POOL_ADD_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_DEL_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
|
||||
NETDEV_CMD_PAGE_POOL_STATS_GET,
|
||||
NETDEV_CMD_QUEUE_GET,
|
||||
NETDEV_CMD_NAPI_GET,
|
||||
NETDEV_CMD_QSTATS_GET,
|
||||
NETDEV_CMD_BIND_RX,
|
||||
NETDEV_CMD_NAPI_SET,
|
||||
|
||||
__NETDEV_CMD_MAX,
|
||||
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#define NETDEV_MCGRP_MGMT "mgmt"
|
||||
#define NETDEV_MCGRP_PAGE_POOL "page-pool"
|
||||
|
||||
#endif /* _UAPI_LINUX_NETDEV_H */
|
||||
@@ -164,6 +164,8 @@ enum perf_event_sample_format {
|
||||
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
|
||||
|
||||
PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
|
||||
|
||||
__PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */
|
||||
};
|
||||
|
||||
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
|
||||
@@ -202,10 +204,6 @@ enum perf_branch_sample_type_shift {
|
||||
|
||||
PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, /* save low level index of raw branch records */
|
||||
|
||||
PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */
|
||||
|
||||
PERF_SAMPLE_BRANCH_COUNTERS_SHIFT = 19, /* save occurrences of events on a branch */
|
||||
|
||||
PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
|
||||
};
|
||||
|
||||
@@ -235,10 +233,6 @@ enum perf_branch_sample_type {
|
||||
|
||||
PERF_SAMPLE_BRANCH_HW_INDEX = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT,
|
||||
|
||||
PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,
|
||||
|
||||
PERF_SAMPLE_BRANCH_COUNTERS = 1U << PERF_SAMPLE_BRANCH_COUNTERS_SHIFT,
|
||||
|
||||
PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
|
||||
};
|
||||
|
||||
@@ -259,48 +253,9 @@ enum {
|
||||
PERF_BR_COND_RET = 10, /* conditional function return */
|
||||
PERF_BR_ERET = 11, /* exception return */
|
||||
PERF_BR_IRQ = 12, /* irq */
|
||||
PERF_BR_SERROR = 13, /* system error */
|
||||
PERF_BR_NO_TX = 14, /* not in transaction */
|
||||
PERF_BR_EXTEND_ABI = 15, /* extend ABI */
|
||||
PERF_BR_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Common branch speculation outcome classification
|
||||
*/
|
||||
enum {
|
||||
PERF_BR_SPEC_NA = 0, /* Not available */
|
||||
PERF_BR_SPEC_WRONG_PATH = 1, /* Speculative but on wrong path */
|
||||
PERF_BR_NON_SPEC_CORRECT_PATH = 2, /* Non-speculative but on correct path */
|
||||
PERF_BR_SPEC_CORRECT_PATH = 3, /* Speculative and on correct path */
|
||||
PERF_BR_SPEC_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
PERF_BR_NEW_FAULT_ALGN = 0, /* Alignment fault */
|
||||
PERF_BR_NEW_FAULT_DATA = 1, /* Data fault */
|
||||
PERF_BR_NEW_FAULT_INST = 2, /* Inst fault */
|
||||
PERF_BR_NEW_ARCH_1 = 3, /* Architecture specific */
|
||||
PERF_BR_NEW_ARCH_2 = 4, /* Architecture specific */
|
||||
PERF_BR_NEW_ARCH_3 = 5, /* Architecture specific */
|
||||
PERF_BR_NEW_ARCH_4 = 6, /* Architecture specific */
|
||||
PERF_BR_NEW_ARCH_5 = 7, /* Architecture specific */
|
||||
PERF_BR_NEW_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
PERF_BR_PRIV_UNKNOWN = 0,
|
||||
PERF_BR_PRIV_USER = 1,
|
||||
PERF_BR_PRIV_KERNEL = 2,
|
||||
PERF_BR_PRIV_HV = 3,
|
||||
};
|
||||
|
||||
#define PERF_BR_ARM64_FIQ PERF_BR_NEW_ARCH_1
|
||||
#define PERF_BR_ARM64_DEBUG_HALT PERF_BR_NEW_ARCH_2
|
||||
#define PERF_BR_ARM64_DEBUG_EXIT PERF_BR_NEW_ARCH_3
|
||||
#define PERF_BR_ARM64_DEBUG_INST PERF_BR_NEW_ARCH_4
|
||||
#define PERF_BR_ARM64_DEBUG_DATA PERF_BR_NEW_ARCH_5
|
||||
|
||||
#define PERF_SAMPLE_BRANCH_PLM_ALL \
|
||||
(PERF_SAMPLE_BRANCH_USER|\
|
||||
PERF_SAMPLE_BRANCH_KERNEL|\
|
||||
@@ -378,15 +333,12 @@ enum perf_event_read_format {
|
||||
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
|
||||
#define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */
|
||||
#define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */
|
||||
#define PERF_ATTR_SIZE_VER8 136 /* add: config3 */
|
||||
|
||||
/*
|
||||
* Hardware event_id to monitor via a performance monitoring event:
|
||||
*
|
||||
* @sample_max_stack: Max number of frame pointers in a callchain,
|
||||
* should be < /proc/sys/kernel/perf_event_max_stack
|
||||
* Max number of entries of branch stack
|
||||
* should be < hardware limit
|
||||
*/
|
||||
struct perf_event_attr {
|
||||
|
||||
@@ -513,16 +465,7 @@ struct perf_event_attr {
|
||||
__u16 sample_max_stack;
|
||||
__u16 __reserved_2;
|
||||
__u32 aux_sample_size;
|
||||
|
||||
union {
|
||||
__u32 aux_action;
|
||||
struct {
|
||||
__u32 aux_start_paused : 1, /* start AUX area tracing paused */
|
||||
aux_pause : 1, /* on overflow, pause AUX area tracing */
|
||||
aux_resume : 1, /* on overflow, resume AUX area tracing */
|
||||
__reserved_3 : 29;
|
||||
};
|
||||
};
|
||||
__u32 __reserved_3;
|
||||
|
||||
/*
|
||||
* User provided data if sigtrap=1, passed back to user via
|
||||
@@ -531,8 +474,6 @@ struct perf_event_attr {
|
||||
* truncated accordingly on 32 bit architectures.
|
||||
*/
|
||||
__u64 sig_data;
|
||||
|
||||
__u64 config3; /* extension of config2 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -997,12 +938,6 @@ enum perf_event_type {
|
||||
* { u64 nr;
|
||||
* { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
|
||||
* { u64 from, to, flags } lbr[nr];
|
||||
* #
|
||||
* # The format of the counters is decided by the
|
||||
* # "branch_counter_nr" and "branch_counter_width",
|
||||
* # which are defined in the ABI.
|
||||
* #
|
||||
* { u64 counters; } cntr[nr] && PERF_SAMPLE_BRANCH_COUNTERS
|
||||
* } && PERF_SAMPLE_BRANCH_STACK
|
||||
*
|
||||
* { u64 abi; # enum perf_sample_regs_abi
|
||||
@@ -1360,14 +1295,9 @@ union perf_mem_data_src {
|
||||
#define PERF_MEM_LVLNUM_L2 0x02 /* L2 */
|
||||
#define PERF_MEM_LVLNUM_L3 0x03 /* L3 */
|
||||
#define PERF_MEM_LVLNUM_L4 0x04 /* L4 */
|
||||
#define PERF_MEM_LVLNUM_L2_MHB 0x05 /* L2 Miss Handling Buffer */
|
||||
#define PERF_MEM_LVLNUM_MSC 0x06 /* Memory-side Cache */
|
||||
/* 0x7 available */
|
||||
#define PERF_MEM_LVLNUM_UNC 0x08 /* Uncached */
|
||||
#define PERF_MEM_LVLNUM_CXL 0x09 /* CXL */
|
||||
#define PERF_MEM_LVLNUM_IO 0x0a /* I/O */
|
||||
/* 5-0xa available */
|
||||
#define PERF_MEM_LVLNUM_ANY_CACHE 0x0b /* Any cache */
|
||||
#define PERF_MEM_LVLNUM_LFB 0x0c /* LFB / L1 Miss Handling Buffer */
|
||||
#define PERF_MEM_LVLNUM_LFB 0x0c /* LFB */
|
||||
#define PERF_MEM_LVLNUM_RAM 0x0d /* RAM */
|
||||
#define PERF_MEM_LVLNUM_PMEM 0x0e /* PMEM */
|
||||
#define PERF_MEM_LVLNUM_NA 0x0f /* N/A */
|
||||
@@ -1383,7 +1313,7 @@ union perf_mem_data_src {
|
||||
#define PERF_MEM_SNOOP_SHIFT 19
|
||||
|
||||
#define PERF_MEM_SNOOPX_FWD 0x01 /* forward */
|
||||
#define PERF_MEM_SNOOPX_PEER 0x02 /* xfer from peer */
|
||||
/* 1 free */
|
||||
#define PERF_MEM_SNOOPX_SHIFT 38
|
||||
|
||||
/* locked instruction */
|
||||
@@ -1433,7 +1363,6 @@ union perf_mem_data_src {
|
||||
* abort: aborting a hardware transaction
|
||||
* cycles: cycles from last branch (or 0 if not supported)
|
||||
* type: branch type
|
||||
* spec: branch speculation info (or 0 if not supported)
|
||||
*/
|
||||
struct perf_branch_entry {
|
||||
__u64 from;
|
||||
@@ -1444,15 +1373,9 @@ struct perf_branch_entry {
|
||||
abort:1, /* transaction abort */
|
||||
cycles:16, /* cycle count to last branch */
|
||||
type:4, /* branch type */
|
||||
spec:2, /* branch speculation info */
|
||||
new_type:4, /* additional branch type */
|
||||
priv:3, /* privilege level */
|
||||
reserved:31;
|
||||
reserved:40;
|
||||
};
|
||||
|
||||
/* Size of used info bits in struct perf_branch_entry */
|
||||
#define PERF_BRANCH_ENTRY_INFO_BITS_MAX 33
|
||||
|
||||
union perf_sample_weight {
|
||||
__u64 full;
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
|
||||
@@ -204,6 +204,37 @@ struct tc_u32_pcnt {
|
||||
|
||||
#define TC_U32_MAXDEPTH 8
|
||||
|
||||
|
||||
/* RSVP filter */
|
||||
|
||||
enum {
|
||||
TCA_RSVP_UNSPEC,
|
||||
TCA_RSVP_CLASSID,
|
||||
TCA_RSVP_DST,
|
||||
TCA_RSVP_SRC,
|
||||
TCA_RSVP_PINFO,
|
||||
TCA_RSVP_POLICE,
|
||||
TCA_RSVP_ACT,
|
||||
__TCA_RSVP_MAX
|
||||
};
|
||||
|
||||
#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
|
||||
|
||||
struct tc_rsvp_gpi {
|
||||
__u32 key;
|
||||
__u32 mask;
|
||||
int offset;
|
||||
};
|
||||
|
||||
struct tc_rsvp_pinfo {
|
||||
struct tc_rsvp_gpi dpi;
|
||||
struct tc_rsvp_gpi spi;
|
||||
__u8 protocol;
|
||||
__u8 tunnelid;
|
||||
__u8 tunnelhdr;
|
||||
__u8 pad;
|
||||
};
|
||||
|
||||
/* ROUTE filter */
|
||||
|
||||
enum {
|
||||
@@ -234,6 +265,22 @@ enum {
|
||||
|
||||
#define TCA_FW_MAX (__TCA_FW_MAX - 1)
|
||||
|
||||
/* TC index filter */
|
||||
|
||||
enum {
|
||||
TCA_TCINDEX_UNSPEC,
|
||||
TCA_TCINDEX_HASH,
|
||||
TCA_TCINDEX_MASK,
|
||||
TCA_TCINDEX_SHIFT,
|
||||
TCA_TCINDEX_FALL_THROUGH,
|
||||
TCA_TCINDEX_CLASSID,
|
||||
TCA_TCINDEX_POLICE,
|
||||
TCA_TCINDEX_ACT,
|
||||
__TCA_TCINDEX_MAX
|
||||
};
|
||||
|
||||
#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
|
||||
|
||||
/* Flow filter */
|
||||
|
||||
enum {
|
||||
|
||||
@@ -457,6 +457,115 @@ enum {
|
||||
|
||||
#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1)
|
||||
|
||||
|
||||
/* CBQ section */
|
||||
|
||||
#define TC_CBQ_MAXPRIO 8
|
||||
#define TC_CBQ_MAXLEVEL 8
|
||||
#define TC_CBQ_DEF_EWMA 5
|
||||
|
||||
struct tc_cbq_lssopt {
|
||||
unsigned char change;
|
||||
unsigned char flags;
|
||||
#define TCF_CBQ_LSS_BOUNDED 1
|
||||
#define TCF_CBQ_LSS_ISOLATED 2
|
||||
unsigned char ewma_log;
|
||||
unsigned char level;
|
||||
#define TCF_CBQ_LSS_FLAGS 1
|
||||
#define TCF_CBQ_LSS_EWMA 2
|
||||
#define TCF_CBQ_LSS_MAXIDLE 4
|
||||
#define TCF_CBQ_LSS_MINIDLE 8
|
||||
#define TCF_CBQ_LSS_OFFTIME 0x10
|
||||
#define TCF_CBQ_LSS_AVPKT 0x20
|
||||
__u32 maxidle;
|
||||
__u32 minidle;
|
||||
__u32 offtime;
|
||||
__u32 avpkt;
|
||||
};
|
||||
|
||||
struct tc_cbq_wrropt {
|
||||
unsigned char flags;
|
||||
unsigned char priority;
|
||||
unsigned char cpriority;
|
||||
unsigned char __reserved;
|
||||
__u32 allot;
|
||||
__u32 weight;
|
||||
};
|
||||
|
||||
struct tc_cbq_ovl {
|
||||
unsigned char strategy;
|
||||
#define TC_CBQ_OVL_CLASSIC 0
|
||||
#define TC_CBQ_OVL_DELAY 1
|
||||
#define TC_CBQ_OVL_LOWPRIO 2
|
||||
#define TC_CBQ_OVL_DROP 3
|
||||
#define TC_CBQ_OVL_RCLASSIC 4
|
||||
unsigned char priority2;
|
||||
__u16 pad;
|
||||
__u32 penalty;
|
||||
};
|
||||
|
||||
struct tc_cbq_police {
|
||||
unsigned char police;
|
||||
unsigned char __res1;
|
||||
unsigned short __res2;
|
||||
};
|
||||
|
||||
struct tc_cbq_fopt {
|
||||
__u32 split;
|
||||
__u32 defmap;
|
||||
__u32 defchange;
|
||||
};
|
||||
|
||||
struct tc_cbq_xstats {
|
||||
__u32 borrows;
|
||||
__u32 overactions;
|
||||
__s32 avgidle;
|
||||
__s32 undertime;
|
||||
};
|
||||
|
||||
enum {
|
||||
TCA_CBQ_UNSPEC,
|
||||
TCA_CBQ_LSSOPT,
|
||||
TCA_CBQ_WRROPT,
|
||||
TCA_CBQ_FOPT,
|
||||
TCA_CBQ_OVL_STRATEGY,
|
||||
TCA_CBQ_RATE,
|
||||
TCA_CBQ_RTAB,
|
||||
TCA_CBQ_POLICE,
|
||||
__TCA_CBQ_MAX,
|
||||
};
|
||||
|
||||
#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1)
|
||||
|
||||
/* dsmark section */
|
||||
|
||||
enum {
|
||||
TCA_DSMARK_UNSPEC,
|
||||
TCA_DSMARK_INDICES,
|
||||
TCA_DSMARK_DEFAULT_INDEX,
|
||||
TCA_DSMARK_SET_TC_INDEX,
|
||||
TCA_DSMARK_MASK,
|
||||
TCA_DSMARK_VALUE,
|
||||
__TCA_DSMARK_MAX,
|
||||
};
|
||||
|
||||
#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1)
|
||||
|
||||
/* ATM section */
|
||||
|
||||
enum {
|
||||
TCA_ATM_UNSPEC,
|
||||
TCA_ATM_FD, /* file/socket descriptor */
|
||||
TCA_ATM_PTR, /* pointer to descriptor - later */
|
||||
TCA_ATM_HDR, /* LL header */
|
||||
TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */
|
||||
TCA_ATM_ADDR, /* PVC address (for output only) */
|
||||
TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */
|
||||
__TCA_ATM_MAX,
|
||||
};
|
||||
|
||||
#define TCA_ATM_MAX (__TCA_ATM_MAX - 1)
|
||||
|
||||
/* Network emulator */
|
||||
|
||||
enum {
|
||||
|
||||
@@ -41,14 +41,14 @@ fi
|
||||
# due to https://bugs.gentoo.org/794601) so let's just point the script to
|
||||
# commits referring to versions of libelf that actually can be built
|
||||
rm -rf elfutils
|
||||
git clone https://sourceware.org/git/elfutils.git
|
||||
git clone git://sourceware.org/git/elfutils.git
|
||||
(
|
||||
cd elfutils
|
||||
git checkout 67a187d4c1790058fc7fd218317851cb68bb087c
|
||||
git checkout 83251d4091241acddbdcf16f814e3bc6ef3df49a
|
||||
git log --oneline -1
|
||||
|
||||
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
||||
sed -i 's/^\(NO_UNDEFINED=\).*/\1/' configure.ac
|
||||
find -name Makefile.am | xargs sed -i 's/,--no-undefined//'
|
||||
|
||||
# ASan isn't compatible with -Wl,-z,defs either:
|
||||
# https://clang.llvm.org/docs/AddressSanitizer.html#usage
|
||||
@@ -62,7 +62,6 @@ fi
|
||||
|
||||
autoreconf -i -f
|
||||
if ! ./configure --enable-maintainer-mode --disable-debuginfod --disable-libdebuginfod \
|
||||
--disable-demangler --without-bzlib --without-lzma --without-zstd \
|
||||
CC="$CC" CFLAGS="-Wno-error $CFLAGS" CXX="$CXX" CXXFLAGS="-Wno-error $CXXFLAGS" LDFLAGS="$CFLAGS"; then
|
||||
cat config.log
|
||||
exit 1
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
usage () {
|
||||
echo "USAGE: ./mailmap-update.sh <libbpf-repo> <linux-repo>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
LIBBPF_REPO="${1-""}"
|
||||
LINUX_REPO="${2-""}"
|
||||
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ]; then
|
||||
echo "Error: libbpf or linux repos are not specified"
|
||||
usage
|
||||
fi
|
||||
|
||||
LIBBPF_MAILMAP="${LIBBPF_REPO}/.mailmap"
|
||||
LINUX_MAILMAP="${LINUX_REPO}/.mailmap"
|
||||
|
||||
tmpfile="$(mktemp)"
|
||||
cleanup() {
|
||||
rm -f "${tmpfile}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
grep_lines() {
|
||||
local pattern="$1"
|
||||
local file="$2"
|
||||
grep "${pattern}" "${file}" || true
|
||||
}
|
||||
|
||||
while read -r email; do
|
||||
grep_lines "${email}$" "${LINUX_MAILMAP}" >> "${tmpfile}"
|
||||
done < <(git log --format='<%ae>' | sort -u)
|
||||
|
||||
sort -u "${tmpfile}" > "${LIBBPF_MAILMAP}"
|
||||
@@ -42,11 +42,8 @@ PATH_MAP=( \
|
||||
[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/fcntl.h]=include/uapi/linux/fcntl.h \
|
||||
[tools/include/uapi/linux/openat2.h]=include/uapi/linux/openat2.h \
|
||||
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||
[tools/include/uapi/linux/netdev.h]=include/uapi/linux/netdev.h \
|
||||
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||
[tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
|
||||
[tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
|
||||
@@ -54,8 +51,8 @@ PATH_MAP=( \
|
||||
[Documentation/bpf/libbpf]=docs \
|
||||
)
|
||||
|
||||
LIBBPF_PATHS=("${!PATH_MAP[@]}" ":^tools/lib/bpf/Makefile" ":^tools/lib/bpf/Build" ":^tools/lib/bpf/.gitignore" ":^tools/include/tools/libc_compat.h")
|
||||
LIBBPF_VIEW_PATHS=("${PATH_MAP[@]}")
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
|
||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
|
||||
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
||||
|
||||
@@ -88,9 +85,7 @@ commit_desc()
|
||||
# $2 - paths filter
|
||||
commit_signature()
|
||||
{
|
||||
local ref=$1
|
||||
shift
|
||||
git show --pretty='("%s")|%aI|%b' --shortstat $ref -- "${@-.}" | tr '\n' '|'
|
||||
git show --pretty='("%s")|%aI|%b' --shortstat $1 -- ${2-.} | tr '\n' '|'
|
||||
}
|
||||
|
||||
# Cherry-pick commits touching libbpf-related files
|
||||
@@ -109,7 +104,7 @@ cherry_pick_commits()
|
||||
local libbpf_conflict_cnt
|
||||
local desc
|
||||
|
||||
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} -- "${LIBBPF_PATHS[@]}")
|
||||
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||
for new_commit in ${new_commits}; do
|
||||
desc="$(commit_desc ${new_commit})"
|
||||
signature="$(commit_signature ${new_commit} "${LIBBPF_PATHS[@]}")"
|
||||
@@ -143,7 +138,7 @@ cherry_pick_commits()
|
||||
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)
|
||||
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
|
||||
conflict_cnt=$(git diff --name-only | wc -l)
|
||||
prompt_resolution=1
|
||||
|
||||
@@ -262,7 +257,7 @@ if ((${COMMIT_CNT} <= 0)); then
|
||||
fi
|
||||
|
||||
# Exclude baseline commit and generate nice cover letter with summary
|
||||
git format-patch --no-signature ${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 is time to re-apply libbpf-related linux patches to libbpf repo
|
||||
cd_to ${LIBBPF_REPO}
|
||||
@@ -289,28 +284,12 @@ cd_to ${LIBBPF_REPO}
|
||||
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 -s -m "sync: auto-generate latest BPF helpers
|
||||
git commit -m "sync: auto-generate latest BPF helpers
|
||||
|
||||
Latest changes to BPF helper definitions.
|
||||
" -- src/bpf_helper_defs.h
|
||||
fi
|
||||
|
||||
echo "Regenerating .mailmap..."
|
||||
cd_to "${LINUX_REPO}"
|
||||
git checkout "${TIP_SYM_REF}"
|
||||
cd_to "${LIBBPF_REPO}"
|
||||
"${LIBBPF_REPO}"/scripts/mailmap-update.sh "${LIBBPF_REPO}" "${LINUX_REPO}"
|
||||
# if anything changed, commit it
|
||||
mailmap_changes=$(git status --porcelain .mailmap | wc -l)
|
||||
if ((${mailmap_changes} == 1)); then
|
||||
git add .mailmap
|
||||
git commit -s -m "sync: update .mailmap
|
||||
|
||||
Update .mailmap based on libbpf's list of contributors and on the latest
|
||||
.mailmap version in the upstream repository.
|
||||
" -- .mailmap
|
||||
fi
|
||||
|
||||
# Use generated cover-letter as a template for "sync commit" with
|
||||
# baseline and checkpoint commits from kernel repo (and leave summary
|
||||
# from cover letter intact, of course)
|
||||
@@ -327,7 +306,7 @@ Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
|
||||
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
||||
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
||||
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
||||
git commit -s --file=-
|
||||
git commit --file=-
|
||||
|
||||
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
||||
|
||||
@@ -337,10 +316,10 @@ cd_to ${LINUX_REPO}
|
||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||
git ls-files -- "${LIBBPF_VIEW_PATHS[@]}" | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
|
||||
|
||||
cd_to ${LIBBPF_REPO}
|
||||
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..."
|
||||
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||
|
||||
21
src/Makefile
21
src/Makefile
@@ -9,7 +9,7 @@ else
|
||||
endif
|
||||
|
||||
LIBBPF_MAJOR_VERSION := 1
|
||||
LIBBPF_MINOR_VERSION := 6
|
||||
LIBBPF_MINOR_VERSION := 1
|
||||
LIBBPF_PATCH_VERSION := 0
|
||||
LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
|
||||
LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
|
||||
@@ -26,7 +26,6 @@ endef
|
||||
|
||||
$(call allow-override,CC,$(CROSS_COMPILE)cc)
|
||||
$(call allow-override,LD,$(CROSS_COMPILE)ld)
|
||||
PKG_CONFIG ?= pkg-config
|
||||
|
||||
TOPDIR = ..
|
||||
|
||||
@@ -36,18 +35,13 @@ ALL_CFLAGS := $(INCLUDES)
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
|
||||
ALL_CFLAGS += $(CFLAGS) \
|
||||
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
|
||||
-Wno-unknown-warning-option -Wno-format-overflow \
|
||||
$(EXTRA_CFLAGS)
|
||||
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(EXTRA_CFLAGS)
|
||||
ALL_LDFLAGS += $(LDFLAGS) $(EXTRA_LDFLAGS)
|
||||
|
||||
ifeq ($(shell command -v $(PKG_CONFIG) 2> /dev/null),)
|
||||
NO_PKG_CONFIG := 1
|
||||
endif
|
||||
ifdef NO_PKG_CONFIG
|
||||
ALL_LDFLAGS += -lelf -lz
|
||||
else
|
||||
PKG_CONFIG ?= pkg-config
|
||||
ALL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libelf zlib)
|
||||
ALL_LDFLAGS += $(shell $(PKG_CONFIG) --libs libelf zlib)
|
||||
endif
|
||||
@@ -58,7 +52,7 @@ STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o \
|
||||
btf_dump.o hashmap.o ringbuf.o strset.o linker.o gen_loader.o \
|
||||
relo_core.o usdt.o zip.o elf.o features.o btf_iter.o btf_relocate.o
|
||||
relo_core.o usdt.o
|
||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||
|
||||
@@ -83,8 +77,7 @@ INSTALL = install
|
||||
|
||||
DESTDIR ?=
|
||||
|
||||
HOSTARCH = $(firstword $(subst -, ,$(shell $(CC) -dumpmachine)))
|
||||
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(HOSTARCH)),)
|
||||
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(shell uname -m)),)
|
||||
LIBSUBDIR := lib64
|
||||
else
|
||||
LIBSUBDIR := lib
|
||||
@@ -122,13 +115,13 @@ $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
|
||||
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||
$^ $(ALL_LDFLAGS) -o $@
|
||||
|
||||
$(OBJDIR)/libbpf.pc: force | $(OBJDIR)
|
||||
$(OBJDIR)/libbpf.pc: force
|
||||
$(Q)sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||
-e "s|@LIBDIR@|$(LIBDIR_PC)|" \
|
||||
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
||||
< libbpf.pc.template > $@
|
||||
|
||||
$(OBJDIR) $(STATIC_OBJDIR) $(SHARED_OBJDIR):
|
||||
$(STATIC_OBJDIR) $(SHARED_OBJDIR):
|
||||
$(call msg,MKDIR,$@)
|
||||
$(Q)mkdir -p $@
|
||||
|
||||
|
||||
350
src/bpf.c
350
src/bpf.c
@@ -103,9 +103,9 @@ int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts)
|
||||
* [0] https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/
|
||||
* [1] d05512618056 ("bpf: Add bpf_ktime_get_coarse_ns helper")
|
||||
*/
|
||||
int probe_memcg_account(int token_fd)
|
||||
int probe_memcg_account(void)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_EMIT_CALL(BPF_FUNC_ktime_get_coarse_ns),
|
||||
BPF_EXIT_INSN(),
|
||||
@@ -120,9 +120,6 @@ int probe_memcg_account(int token_fd)
|
||||
attr.insns = ptr_to_u64(insns);
|
||||
attr.insn_cnt = insn_cnt;
|
||||
attr.license = ptr_to_u64("GPL");
|
||||
attr.prog_token_fd = token_fd;
|
||||
if (token_fd)
|
||||
attr.prog_flags |= BPF_F_TOKEN_FD;
|
||||
|
||||
prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, attr_sz);
|
||||
if (prog_fd >= 0) {
|
||||
@@ -149,7 +146,7 @@ int bump_rlimit_memlock(void)
|
||||
struct rlimit rlim;
|
||||
|
||||
/* if kernel supports memcg-based accounting, skip bumping RLIMIT_MEMLOCK */
|
||||
if (memlock_bumped || feat_supported(NULL, FEAT_MEMCG_ACCOUNT))
|
||||
if (memlock_bumped || kernel_supports(NULL, FEAT_MEMCG_ACCOUNT))
|
||||
return 0;
|
||||
|
||||
memlock_bumped = true;
|
||||
@@ -172,7 +169,7 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
__u32 max_entries,
|
||||
const struct bpf_map_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
@@ -184,7 +181,7 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
attr.map_type = map_type;
|
||||
if (map_name && feat_supported(NULL, FEAT_PROG_NAME))
|
||||
if (map_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||
libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
@@ -194,7 +191,6 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0);
|
||||
attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0);
|
||||
attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0);
|
||||
attr.value_type_btf_obj_fd = OPTS_GET(opts, value_type_btf_obj_fd, 0);
|
||||
|
||||
attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
|
||||
attr.map_flags = OPTS_GET(opts, map_flags, 0);
|
||||
@@ -202,8 +198,6 @@ int bpf_map_create(enum bpf_map_type map_type,
|
||||
attr.numa_node = OPTS_GET(opts, numa_node, 0);
|
||||
attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0);
|
||||
|
||||
attr.map_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
@@ -236,9 +230,9 @@ alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
||||
int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *opts)
|
||||
const struct bpf_prog_load_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, fd_array_cnt);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, fd_array);
|
||||
void *finfo = NULL, *linfo = NULL;
|
||||
const char *func_info, *line_info;
|
||||
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
||||
@@ -267,9 +261,8 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
attr.prog_flags = OPTS_GET(opts, prog_flags, 0);
|
||||
attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0);
|
||||
attr.kern_version = OPTS_GET(opts, kern_version, 0);
|
||||
attr.prog_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
if (prog_name && feat_supported(NULL, FEAT_PROG_NAME))
|
||||
if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME))
|
||||
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
|
||||
attr.license = ptr_to_u64(license);
|
||||
|
||||
@@ -297,6 +290,10 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
|
||||
if (!!log_buf != !!log_size)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (log_level > (4 | 2 | 1))
|
||||
return libbpf_err(-EINVAL);
|
||||
if (log_level && !log_buf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
func_info_rec_size = OPTS_GET(opts, func_info_rec_size, 0);
|
||||
func_info = OPTS_GET(opts, func_info, NULL);
|
||||
@@ -311,7 +308,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
attr.line_info_cnt = OPTS_GET(opts, line_info_cnt, 0);
|
||||
|
||||
attr.fd_array = ptr_to_u64(OPTS_GET(opts, fd_array, NULL));
|
||||
attr.fd_array_cnt = OPTS_GET(opts, fd_array_cnt, 0);
|
||||
|
||||
if (log_level) {
|
||||
attr.log_buf = ptr_to_u64(log_buf);
|
||||
@@ -320,7 +316,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
}
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
@@ -361,7 +356,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
}
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||
if (fd >= 0)
|
||||
goto done;
|
||||
}
|
||||
@@ -376,7 +370,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
attr.log_level = 1;
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
|
||||
OPTS_SET(opts, log_true_size, attr.log_true_size);
|
||||
}
|
||||
done:
|
||||
/* free() doesn't affect errno, so we don't need to restore it */
|
||||
@@ -580,30 +573,20 @@ int bpf_map_update_batch(int fd, const void *keys, const void *values, __u32 *co
|
||||
(void *)keys, (void *)values, count, opts);
|
||||
}
|
||||
|
||||
int bpf_obj_pin_opts(int fd, const char *pathname, const struct bpf_obj_pin_opts *opts)
|
||||
int bpf_obj_pin(int fd, const char *pathname)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, path_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_obj_pin_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.path_fd = OPTS_GET(opts, path_fd, 0);
|
||||
attr.pathname = ptr_to_u64((void *)pathname);
|
||||
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
||||
attr.bpf_fd = fd;
|
||||
|
||||
ret = sys_bpf(BPF_OBJ_PIN, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_obj_pin(int fd, const char *pathname)
|
||||
{
|
||||
return bpf_obj_pin_opts(fd, pathname, NULL);
|
||||
}
|
||||
|
||||
int bpf_obj_get(const char *pathname)
|
||||
{
|
||||
return bpf_obj_get_opts(pathname, NULL);
|
||||
@@ -611,7 +594,7 @@ int bpf_obj_get(const char *pathname)
|
||||
|
||||
int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, path_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, file_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
@@ -619,7 +602,6 @@ int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.path_fd = OPTS_GET(opts, path_fd, 0);
|
||||
attr.pathname = ptr_to_u64((void *)pathname);
|
||||
attr.file_flags = OPTS_GET(opts, file_flags, 0);
|
||||
|
||||
@@ -637,89 +619,55 @@ int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
||||
return bpf_prog_attach_opts(prog_fd, target_fd, type, &opts);
|
||||
}
|
||||
|
||||
int bpf_prog_attach_opts(int prog_fd, int target, enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts)
|
||||
int bpf_prog_attach_opts(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
|
||||
__u32 relative_id, flags;
|
||||
int ret, relative_fd;
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
relative_id = OPTS_GET(opts, relative_id, 0);
|
||||
relative_fd = OPTS_GET(opts, relative_fd, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
/* validate we don't have unexpected combinations of non-zero fields */
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_fd, 0);
|
||||
attr.expected_revision = OPTS_GET(opts, expected_revision, 0);
|
||||
|
||||
if (relative_id) {
|
||||
attr.attach_flags = flags | BPF_F_ID;
|
||||
attr.relative_id = relative_id;
|
||||
} else {
|
||||
attr.attach_flags = flags;
|
||||
attr.relative_fd = relative_fd;
|
||||
}
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
||||
|
||||
ret = sys_bpf(BPF_PROG_ATTACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_prog_detach_opts(int prog_fd, int target, enum bpf_attach_type type,
|
||||
const struct bpf_prog_detach_opts *opts)
|
||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, expected_revision);
|
||||
__u32 relative_id, flags;
|
||||
int ret, relative_fd;
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_prog_detach_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
relative_id = OPTS_GET(opts, relative_id, 0);
|
||||
relative_fd = OPTS_GET(opts, relative_fd, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
/* validate we don't have unexpected combinations of non-zero fields */
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
attr.expected_revision = OPTS_GET(opts, expected_revision, 0);
|
||||
|
||||
if (relative_id) {
|
||||
attr.attach_flags = flags | BPF_F_ID;
|
||||
attr.relative_id = relative_id;
|
||||
} else {
|
||||
attr.attach_flags = flags;
|
||||
attr.relative_fd = relative_fd;
|
||||
}
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_type = type;
|
||||
|
||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
return bpf_prog_detach_opts(0, target_fd, type, NULL);
|
||||
}
|
||||
|
||||
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
||||
{
|
||||
return bpf_prog_detach_opts(prog_fd, target_fd, type, NULL);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, replace_bpf_fd);
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.target_fd = target_fd;
|
||||
attr.attach_bpf_fd = prog_fd;
|
||||
attr.attach_type = type;
|
||||
|
||||
ret = sys_bpf(BPF_PROG_DETACH, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_link_create(int prog_fd, int target_fd,
|
||||
@@ -727,9 +675,9 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
const struct bpf_link_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, link_create);
|
||||
__u32 target_btf_id, iter_info_len, relative_id;
|
||||
int fd, err, relative_fd;
|
||||
__u32 target_btf_id, iter_info_len;
|
||||
union bpf_attr attr;
|
||||
int fd, err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_link_create_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
@@ -767,7 +715,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TRACE_KPROBE_MULTI:
|
||||
case BPF_TRACE_KPROBE_SESSION:
|
||||
attr.link_create.kprobe_multi.flags = OPTS_GET(opts, kprobe_multi.flags, 0);
|
||||
attr.link_create.kprobe_multi.cnt = OPTS_GET(opts, kprobe_multi.cnt, 0);
|
||||
attr.link_create.kprobe_multi.syms = ptr_to_u64(OPTS_GET(opts, kprobe_multi.syms, 0));
|
||||
@@ -776,19 +723,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
if (!OPTS_ZEROED(opts, kprobe_multi))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TRACE_UPROBE_MULTI:
|
||||
case BPF_TRACE_UPROBE_SESSION:
|
||||
attr.link_create.uprobe_multi.flags = OPTS_GET(opts, uprobe_multi.flags, 0);
|
||||
attr.link_create.uprobe_multi.cnt = OPTS_GET(opts, uprobe_multi.cnt, 0);
|
||||
attr.link_create.uprobe_multi.path = ptr_to_u64(OPTS_GET(opts, uprobe_multi.path, 0));
|
||||
attr.link_create.uprobe_multi.offsets = ptr_to_u64(OPTS_GET(opts, uprobe_multi.offsets, 0));
|
||||
attr.link_create.uprobe_multi.ref_ctr_offsets = ptr_to_u64(OPTS_GET(opts, uprobe_multi.ref_ctr_offsets, 0));
|
||||
attr.link_create.uprobe_multi.cookies = ptr_to_u64(OPTS_GET(opts, uprobe_multi.cookies, 0));
|
||||
attr.link_create.uprobe_multi.pid = OPTS_GET(opts, uprobe_multi.pid, 0);
|
||||
if (!OPTS_ZEROED(opts, uprobe_multi))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TRACE_RAW_TP:
|
||||
case BPF_TRACE_FENTRY:
|
||||
case BPF_TRACE_FEXIT:
|
||||
case BPF_MODIFY_RETURN:
|
||||
@@ -797,46 +731,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
if (!OPTS_ZEROED(opts, tracing))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_NETFILTER:
|
||||
attr.link_create.netfilter.pf = OPTS_GET(opts, netfilter.pf, 0);
|
||||
attr.link_create.netfilter.hooknum = OPTS_GET(opts, netfilter.hooknum, 0);
|
||||
attr.link_create.netfilter.priority = OPTS_GET(opts, netfilter.priority, 0);
|
||||
attr.link_create.netfilter.flags = OPTS_GET(opts, netfilter.flags, 0);
|
||||
if (!OPTS_ZEROED(opts, netfilter))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_TCX_INGRESS:
|
||||
case BPF_TCX_EGRESS:
|
||||
relative_fd = OPTS_GET(opts, tcx.relative_fd, 0);
|
||||
relative_id = OPTS_GET(opts, tcx.relative_id, 0);
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (relative_id) {
|
||||
attr.link_create.tcx.relative_id = relative_id;
|
||||
attr.link_create.flags |= BPF_F_ID;
|
||||
} else {
|
||||
attr.link_create.tcx.relative_fd = relative_fd;
|
||||
}
|
||||
attr.link_create.tcx.expected_revision = OPTS_GET(opts, tcx.expected_revision, 0);
|
||||
if (!OPTS_ZEROED(opts, tcx))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
case BPF_NETKIT_PRIMARY:
|
||||
case BPF_NETKIT_PEER:
|
||||
relative_fd = OPTS_GET(opts, netkit.relative_fd, 0);
|
||||
relative_id = OPTS_GET(opts, netkit.relative_id, 0);
|
||||
if (relative_fd && relative_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (relative_id) {
|
||||
attr.link_create.netkit.relative_id = relative_id;
|
||||
attr.link_create.flags |= BPF_F_ID;
|
||||
} else {
|
||||
attr.link_create.netkit.relative_fd = relative_fd;
|
||||
}
|
||||
attr.link_create.netkit.expected_revision = OPTS_GET(opts, netkit.expected_revision, 0);
|
||||
if (!OPTS_ZEROED(opts, netkit))
|
||||
return libbpf_err(-EINVAL);
|
||||
break;
|
||||
default:
|
||||
if (!OPTS_ZEROED(opts, flags))
|
||||
return libbpf_err(-EINVAL);
|
||||
@@ -900,17 +794,11 @@ int bpf_link_update(int link_fd, int new_prog_fd,
|
||||
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (OPTS_GET(opts, old_prog_fd, 0) && OPTS_GET(opts, old_map_fd, 0))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.link_update.link_fd = link_fd;
|
||||
attr.link_update.new_prog_fd = new_prog_fd;
|
||||
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
||||
if (OPTS_GET(opts, old_prog_fd, 0))
|
||||
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||
else if (OPTS_GET(opts, old_map_fd, 0))
|
||||
attr.link_update.old_map_fd = OPTS_GET(opts, old_map_fd, 0);
|
||||
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||
|
||||
ret = sys_bpf(BPF_LINK_UPDATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
@@ -929,7 +817,8 @@ int bpf_iter_create(int link_fd)
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
int bpf_prog_query_opts(int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
struct bpf_prog_query_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, query);
|
||||
@@ -940,20 +829,18 @@ int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.query.target_fd = target;
|
||||
attr.query.attach_type = type;
|
||||
attr.query.query_flags = OPTS_GET(opts, query_flags, 0);
|
||||
attr.query.count = OPTS_GET(opts, count, 0);
|
||||
attr.query.prog_ids = ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
|
||||
attr.query.link_ids = ptr_to_u64(OPTS_GET(opts, link_ids, NULL));
|
||||
attr.query.prog_attach_flags = ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
|
||||
attr.query.link_attach_flags = ptr_to_u64(OPTS_GET(opts, link_attach_flags, NULL));
|
||||
|
||||
attr.query.target_fd = target_fd;
|
||||
attr.query.attach_type = type;
|
||||
attr.query.query_flags = OPTS_GET(opts, query_flags, 0);
|
||||
attr.query.prog_cnt = OPTS_GET(opts, prog_cnt, 0);
|
||||
attr.query.prog_ids = ptr_to_u64(OPTS_GET(opts, prog_ids, NULL));
|
||||
attr.query.prog_attach_flags = ptr_to_u64(OPTS_GET(opts, prog_attach_flags, NULL));
|
||||
|
||||
ret = sys_bpf(BPF_PROG_QUERY, &attr, attr_sz);
|
||||
|
||||
OPTS_SET(opts, attach_flags, attr.query.attach_flags);
|
||||
OPTS_SET(opts, revision, attr.query.revision);
|
||||
OPTS_SET(opts, count, attr.query.count);
|
||||
OPTS_SET(opts, prog_cnt, attr.query.prog_cnt);
|
||||
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
@@ -1048,97 +935,56 @@ int bpf_link_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
return bpf_obj_get_next_id(start_id, next_id, BPF_LINK_GET_NEXT_ID);
|
||||
}
|
||||
|
||||
int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
int bpf_prog_get_fd_by_id(__u32 id)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.prog_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_prog_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_prog_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
int bpf_map_get_fd_by_id(__u32 id)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.map_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_map_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_map_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, fd_by_id_token_fd);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.btf_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
attr.fd_by_id_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_btf_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_btf_get_fd_by_id_opts(id, NULL);
|
||||
}
|
||||
|
||||
int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_get_fd_by_id_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.link_id = id;
|
||||
attr.open_flags = OPTS_GET(opts, open_flags, 0);
|
||||
attr.btf_id = id;
|
||||
|
||||
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, attr_sz);
|
||||
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_link_get_fd_by_id(__u32 id)
|
||||
{
|
||||
return bpf_link_get_fd_by_id_opts(id, NULL);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.link_id = id;
|
||||
|
||||
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
||||
@@ -1158,54 +1004,23 @@ int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
||||
return libbpf_err_errno(err);
|
||||
}
|
||||
|
||||
int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, __u32 *info_len)
|
||||
{
|
||||
return bpf_obj_get_info_by_fd(prog_fd, info, info_len);
|
||||
}
|
||||
|
||||
int bpf_map_get_info_by_fd(int map_fd, struct bpf_map_info *info, __u32 *info_len)
|
||||
{
|
||||
return bpf_obj_get_info_by_fd(map_fd, info, info_len);
|
||||
}
|
||||
|
||||
int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u32 *info_len)
|
||||
{
|
||||
return bpf_obj_get_info_by_fd(btf_fd, info, info_len);
|
||||
}
|
||||
|
||||
int bpf_link_get_info_by_fd(int link_fd, struct bpf_link_info *info, __u32 *info_len)
|
||||
{
|
||||
return bpf_obj_get_info_by_fd(link_fd, info, info_len);
|
||||
}
|
||||
|
||||
int bpf_raw_tracepoint_open_opts(int prog_fd, struct bpf_raw_tp_opts *opts)
|
||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_raw_tp_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.raw_tracepoint.name = ptr_to_u64(name);
|
||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||
attr.raw_tracepoint.name = ptr_to_u64(OPTS_GET(opts, tp_name, NULL));
|
||||
attr.raw_tracepoint.cookie = OPTS_GET(opts, cookie, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
int bpf_btf_load(const void *btf_data, size_t btf_size, const struct bpf_btf_load_opts *opts)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_raw_tp_opts, opts, .tp_name = name);
|
||||
|
||||
return bpf_raw_tracepoint_open_opts(prog_fd, &opts);
|
||||
}
|
||||
|
||||
int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, btf_token_fd);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, btf_log_level);
|
||||
union bpf_attr attr;
|
||||
char *log_buf;
|
||||
size_t log_size;
|
||||
@@ -1230,10 +1045,6 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts
|
||||
|
||||
attr.btf = ptr_to_u64(btf_data);
|
||||
attr.btf_size = btf_size;
|
||||
|
||||
attr.btf_flags = OPTS_GET(opts, btf_flags, 0);
|
||||
attr.btf_token_fd = OPTS_GET(opts, token_fd, 0);
|
||||
|
||||
/* log_level == 0 and log_buf != NULL means "try loading without
|
||||
* log_buf, but retry with log_buf and log_level=1 on error", which is
|
||||
* consistent across low-level and high-level BTF and program loading
|
||||
@@ -1252,8 +1063,6 @@ int bpf_btf_load(const void *btf_data, size_t btf_size, struct bpf_btf_load_opts
|
||||
attr.btf_log_level = 1;
|
||||
fd = sys_bpf_fd(BPF_BTF_LOAD, &attr, attr_sz);
|
||||
}
|
||||
|
||||
OPTS_SET(opts, log_true_size, attr.btf_log_true_size);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -1314,20 +1123,3 @@ int bpf_prog_bind_map(int prog_fd, int map_fd,
|
||||
ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, attr_sz);
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_token_create(int bpffs_fd, struct bpf_token_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, token_create);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_token_create_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.token_create.bpffs_fd = bpffs_fd;
|
||||
attr.token_create.flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_TOKEN_CREATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
333
src/bpf.h
333
src/bpf.h
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
|
||||
/*
|
||||
* Common BPF ELF operations.
|
||||
* common eBPF ELF operations.
|
||||
*
|
||||
* Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
|
||||
* Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
|
||||
@@ -35,7 +35,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBBPF_API int libbpf_set_memlock_rlim(size_t memlock_bytes);
|
||||
int libbpf_set_memlock_rlim(size_t memlock_bytes);
|
||||
|
||||
struct bpf_map_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -51,12 +51,8 @@ struct bpf_map_create_opts {
|
||||
|
||||
__u32 numa_node;
|
||||
__u32 map_ifindex;
|
||||
__s32 value_type_btf_obj_fd;
|
||||
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_map_create_opts__last_field token_fd
|
||||
#define bpf_map_create_opts__last_field map_ifindex
|
||||
|
||||
LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
@@ -100,24 +96,13 @@ struct bpf_prog_load_opts {
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
char *log_buf;
|
||||
/* output: actual total log contents size (including terminating zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
__u32 token_fd;
|
||||
|
||||
/* if set, provides the length of fd_array */
|
||||
__u32 fd_array_cnt;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_load_opts__last_field fd_array_cnt
|
||||
#define bpf_prog_load_opts__last_field log_buf
|
||||
|
||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *opts);
|
||||
const struct bpf_prog_load_opts *opts);
|
||||
|
||||
/* Flags to direct loading requirements */
|
||||
#define MAPS_RELAX_COMPAT 0x01
|
||||
@@ -132,21 +117,11 @@ struct bpf_btf_load_opts {
|
||||
char *log_buf;
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
/* output: actual total log contents size (including terminating zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
|
||||
__u32 btf_flags;
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_btf_load_opts__last_field token_fd
|
||||
#define bpf_btf_load_opts__last_field log_size
|
||||
|
||||
LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size,
|
||||
struct bpf_btf_load_opts *opts);
|
||||
const struct bpf_btf_load_opts *opts);
|
||||
|
||||
LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||
__u64 flags);
|
||||
@@ -193,14 +168,10 @@ LIBBPF_API int bpf_map_delete_batch(int fd, const void *keys,
|
||||
/**
|
||||
* @brief **bpf_map_lookup_batch()** allows for batch lookup of BPF map elements.
|
||||
*
|
||||
* The parameter *in_batch* is the address of the first element in the batch to
|
||||
* read. *out_batch* is an output parameter that should be passed as *in_batch*
|
||||
* to subsequent calls to **bpf_map_lookup_batch()**. NULL can be passed for
|
||||
* *in_batch* to indicate that the batched lookup starts from the beginning of
|
||||
* the map. Both *in_batch* and *out_batch* must point to memory large enough to
|
||||
* hold a single key, except for maps of type **BPF_MAP_TYPE_{HASH, PERCPU_HASH,
|
||||
* LRU_HASH, LRU_PERCPU_HASH}**, for which the memory size must be at
|
||||
* least 4 bytes wide regardless of key size.
|
||||
* The parameter *in_batch* is the address of the first element in the batch to read.
|
||||
* *out_batch* is an output parameter that should be passed as *in_batch* to subsequent
|
||||
* calls to **bpf_map_lookup_batch()**. NULL can be passed for *in_batch* to indicate
|
||||
* that the batched lookup starts from the beginning of the map.
|
||||
*
|
||||
* The *keys* and *values* are output parameters which must point to memory large enough to
|
||||
* hold *count* items based on the key and value size of the map *map_fd*. The *keys*
|
||||
@@ -233,10 +204,7 @@ LIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch,
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param in_batch address of the first element in batch to read, can pass NULL to
|
||||
* get address of the first element in *out_batch*. If not NULL, must be large
|
||||
* enough to hold a key. For **BPF_MAP_TYPE_{HASH, PERCPU_HASH, LRU_HASH,
|
||||
* LRU_PERCPU_HASH}**, the memory size must be at least 4 bytes wide regardless
|
||||
* of key size.
|
||||
* get address of the first element in *out_batch*
|
||||
* @param out_batch output parameter that should be passed to next call as *in_batch*
|
||||
* @param keys pointer to an array of *count* keys
|
||||
* @param values pointer to an array large enough for *count* values
|
||||
@@ -302,96 +270,36 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values
|
||||
__u32 *count,
|
||||
const struct bpf_map_batch_opts *opts);
|
||||
|
||||
struct bpf_obj_pin_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
__u32 file_flags;
|
||||
int path_fd;
|
||||
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_obj_pin_opts__last_field path_fd
|
||||
|
||||
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
||||
LIBBPF_API int bpf_obj_pin_opts(int fd, const char *pathname,
|
||||
const struct bpf_obj_pin_opts *opts);
|
||||
|
||||
struct bpf_obj_get_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
__u32 file_flags;
|
||||
int path_fd;
|
||||
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_obj_get_opts__last_field path_fd
|
||||
#define bpf_obj_get_opts__last_field file_flags
|
||||
|
||||
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
||||
LIBBPF_API int bpf_obj_get(const char *pathname);
|
||||
LIBBPF_API int bpf_obj_get_opts(const char *pathname,
|
||||
const struct bpf_obj_get_opts *opts);
|
||||
|
||||
struct bpf_prog_attach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
unsigned int flags;
|
||||
int replace_prog_fd;
|
||||
};
|
||||
#define bpf_prog_attach_opts__last_field replace_prog_fd
|
||||
|
||||
LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type, unsigned int flags);
|
||||
LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
struct bpf_prog_attach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
union {
|
||||
int replace_prog_fd;
|
||||
int replace_fd;
|
||||
};
|
||||
int relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_attach_opts__last_field expected_revision
|
||||
|
||||
struct bpf_prog_detach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
int relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_detach_opts__last_field expected_revision
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_attach_opts()** attaches the BPF program corresponding to
|
||||
* *prog_fd* to a *target* which can represent a file descriptor or netdevice
|
||||
* ifindex.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param target attach location file descriptor or ifindex
|
||||
* @param type attach type for the BPF program
|
||||
* @param opts options for configuring the attachment
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int target,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_detach_opts()** detaches the BPF program corresponding to
|
||||
* *prog_fd* from a *target* which can represent a file descriptor or netdevice
|
||||
* ifindex.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param target detach location file descriptor or ifindex
|
||||
* @param type detach type for the BPF program
|
||||
* @param opts options for configuring the detachment
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_detach_opts(int prog_fd, int target,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_detach_opts *opts);
|
||||
|
||||
union bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */
|
||||
struct bpf_link_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -410,38 +318,13 @@ struct bpf_link_create_opts {
|
||||
const unsigned long *addrs;
|
||||
const __u64 *cookies;
|
||||
} kprobe_multi;
|
||||
struct {
|
||||
__u32 flags;
|
||||
__u32 cnt;
|
||||
const char *path;
|
||||
const unsigned long *offsets;
|
||||
const unsigned long *ref_ctr_offsets;
|
||||
const __u64 *cookies;
|
||||
__u32 pid;
|
||||
} uprobe_multi;
|
||||
struct {
|
||||
__u64 cookie;
|
||||
} tracing;
|
||||
struct {
|
||||
__u32 pf;
|
||||
__u32 hooknum;
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
struct {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
} tcx;
|
||||
struct {
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
} netkit;
|
||||
};
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_link_create_opts__last_field uprobe_multi.pid
|
||||
#define bpf_link_create_opts__last_field kprobe_multi.cookies
|
||||
|
||||
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type,
|
||||
@@ -453,9 +336,8 @@ struct bpf_link_update_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags; /* extra flags */
|
||||
__u32 old_prog_fd; /* expected old program FD */
|
||||
__u32 old_map_fd; /* expected old map FD */
|
||||
};
|
||||
#define bpf_link_update_opts__last_field old_map_fd
|
||||
#define bpf_link_update_opts__last_field old_prog_fd
|
||||
|
||||
LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
|
||||
const struct bpf_link_update_opts *opts);
|
||||
@@ -483,167 +365,36 @@ 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_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
|
||||
struct bpf_get_fd_by_id_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 open_flags; /* permissions requested for the operation on fd */
|
||||
__u32 token_fd;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_get_fd_by_id_opts__last_field token_fd
|
||||
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_map_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_link_get_fd_by_id_opts(__u32 id,
|
||||
const struct bpf_get_fd_by_id_opts *opts);
|
||||
LIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_get_info_by_fd()** obtains information about the BPF
|
||||
* program corresponding to *prog_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
*
|
||||
* @param prog_fd BPF program file descriptor
|
||||
* @param info pointer to **struct bpf_prog_info** that will be populated with
|
||||
* BPF program information
|
||||
* @param info_len pointer to the size of *info*; on success updated with the
|
||||
* number of bytes written to *info*
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_get_info_by_fd(int prog_fd, struct bpf_prog_info *info, __u32 *info_len);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map_get_info_by_fd()** obtains information about the BPF
|
||||
* map corresponding to *map_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
*
|
||||
* @param map_fd BPF map file descriptor
|
||||
* @param info pointer to **struct bpf_map_info** that will be populated with
|
||||
* BPF map information
|
||||
* @param info_len pointer to the size of *info*; on success updated with the
|
||||
* number of bytes written to *info*
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_map_get_info_by_fd(int map_fd, struct bpf_map_info *info, __u32 *info_len);
|
||||
|
||||
/**
|
||||
* @brief **bpf_btf_get_info_by_fd()** obtains information about the
|
||||
* BTF object corresponding to *btf_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
*
|
||||
* @param btf_fd BTF object file descriptor
|
||||
* @param info pointer to **struct bpf_btf_info** that will be populated with
|
||||
* BTF object information
|
||||
* @param info_len pointer to the size of *info*; on success updated with the
|
||||
* number of bytes written to *info*
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_btf_get_info_by_fd(int btf_fd, struct bpf_btf_info *info, __u32 *info_len);
|
||||
|
||||
/**
|
||||
* @brief **bpf_btf_get_info_by_fd()** obtains information about the BPF
|
||||
* link corresponding to *link_fd*.
|
||||
*
|
||||
* Populates up to *info_len* bytes of *info* and updates *info_len* with the
|
||||
* actual number of bytes written to *info*. Note that *info* should be
|
||||
* zero-initialized or initialized as expected by the requested *info*
|
||||
* type. Failing to (zero-)initialize *info* under certain circumstances can
|
||||
* result in this helper returning an error.
|
||||
*
|
||||
* @param link_fd BPF link file descriptor
|
||||
* @param info pointer to **struct bpf_link_info** that will be populated with
|
||||
* BPF link information
|
||||
* @param info_len pointer to the size of *info*; on success updated with the
|
||||
* number of bytes written to *info*
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_link_get_info_by_fd(int link_fd, struct bpf_link_info *info, __u32 *info_len);
|
||||
|
||||
struct bpf_prog_query_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 query_flags;
|
||||
__u32 attach_flags; /* output argument */
|
||||
__u32 *prog_ids;
|
||||
union {
|
||||
/* input+output argument */
|
||||
__u32 prog_cnt;
|
||||
__u32 count;
|
||||
};
|
||||
__u32 prog_cnt; /* input+output argument */
|
||||
__u32 *prog_attach_flags;
|
||||
__u32 *link_ids;
|
||||
__u32 *link_attach_flags;
|
||||
__u64 revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_prog_query_opts__last_field revision
|
||||
#define bpf_prog_query_opts__last_field prog_attach_flags
|
||||
|
||||
/**
|
||||
* @brief **bpf_prog_query_opts()** queries the BPF programs and BPF links
|
||||
* which are attached to *target* which can represent a file descriptor or
|
||||
* netdevice ifindex.
|
||||
*
|
||||
* @param target query location file descriptor or ifindex
|
||||
* @param type attach type for the BPF program
|
||||
* @param opts options for configuring the query
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_prog_query_opts(int target, enum bpf_attach_type type,
|
||||
LIBBPF_API int bpf_prog_query_opts(int target_fd,
|
||||
enum bpf_attach_type type,
|
||||
struct bpf_prog_query_opts *opts);
|
||||
LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type,
|
||||
__u32 query_flags, __u32 *attach_flags,
|
||||
__u32 *prog_ids, __u32 *prog_cnt);
|
||||
|
||||
struct bpf_raw_tp_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
const char *tp_name;
|
||||
__u64 cookie;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_raw_tp_opts__last_field cookie
|
||||
|
||||
LIBBPF_API int bpf_raw_tracepoint_open_opts(int prog_fd, struct bpf_raw_tp_opts *opts);
|
||||
LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd);
|
||||
LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
|
||||
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
|
||||
__u64 *probe_offset, __u64 *probe_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* forward-declaring enums in C++ isn't compatible with pure C enums, so
|
||||
* instead define bpf_enable_stats() as accepting int as an input
|
||||
*/
|
||||
LIBBPF_API int bpf_enable_stats(int type);
|
||||
#else
|
||||
enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */
|
||||
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);
|
||||
#endif
|
||||
|
||||
struct bpf_prog_bind_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -680,30 +431,6 @@ struct bpf_test_run_opts {
|
||||
LIBBPF_API int bpf_prog_test_run_opts(int prog_fd,
|
||||
struct bpf_test_run_opts *opts);
|
||||
|
||||
struct bpf_token_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_token_create_opts__last_field flags
|
||||
|
||||
/**
|
||||
* @brief **bpf_token_create()** creates a new instance of BPF token derived
|
||||
* from specified BPF FS mount point.
|
||||
*
|
||||
* BPF token created with this API can be passed to bpf() syscall for
|
||||
* commands like BPF_PROG_LOAD, BPF_MAP_CREATE, etc.
|
||||
*
|
||||
* @param bpffs_fd FD for BPF FS instance from which to derive a BPF token
|
||||
* instance.
|
||||
* @param opts optional BPF token creation options, can be NULL
|
||||
*
|
||||
* @return BPF token FD > 0, on success; negative error code, otherwise (errno
|
||||
* is also set to the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_token_create(int bpffs_fd,
|
||||
struct bpf_token_create_opts *opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#ifndef __BPF_CORE_READ_H__
|
||||
#define __BPF_CORE_READ_H__
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
/*
|
||||
* enum bpf_field_info_kind is passed as a second argument into
|
||||
* __builtin_preserve_field_info() built-in to get a specific aspect of
|
||||
@@ -46,7 +44,7 @@ enum bpf_enum_value_kind {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||
bpf_probe_read_kernel( \
|
||||
(void *)dst, \
|
||||
(void *)dst, \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
#else
|
||||
@@ -104,7 +102,6 @@ enum bpf_enum_value_kind {
|
||||
case 2: val = *(const unsigned short *)p; break; \
|
||||
case 4: val = *(const unsigned int *)p; break; \
|
||||
case 8: val = *(const unsigned long long *)p; break; \
|
||||
default: val = 0; break; \
|
||||
} \
|
||||
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
||||
if (__CORE_RELO(s, field, SIGNED)) \
|
||||
@@ -114,61 +111,8 @@ enum bpf_enum_value_kind {
|
||||
val; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Write to a bitfield, identified by s->field.
|
||||
* This is the inverse of BPF_CORE_WRITE_BITFIELD().
|
||||
*/
|
||||
#define BPF_CORE_WRITE_BITFIELD(s, field, new_val) ({ \
|
||||
void *p = (void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
||||
unsigned int byte_size = __CORE_RELO(s, field, BYTE_SIZE); \
|
||||
unsigned int lshift = __CORE_RELO(s, field, LSHIFT_U64); \
|
||||
unsigned int rshift = __CORE_RELO(s, field, RSHIFT_U64); \
|
||||
unsigned long long mask, val, nval = new_val; \
|
||||
unsigned int rpad = rshift - lshift; \
|
||||
\
|
||||
asm volatile("" : "+r"(p)); \
|
||||
\
|
||||
switch (byte_size) { \
|
||||
case 1: val = *(unsigned char *)p; break; \
|
||||
case 2: val = *(unsigned short *)p; break; \
|
||||
case 4: val = *(unsigned int *)p; break; \
|
||||
case 8: val = *(unsigned long long *)p; break; \
|
||||
} \
|
||||
\
|
||||
mask = (~0ULL << rshift) >> lshift; \
|
||||
val = (val & ~mask) | ((nval << rpad) & mask); \
|
||||
\
|
||||
switch (byte_size) { \
|
||||
case 1: *(unsigned char *)p = val; break; \
|
||||
case 2: *(unsigned short *)p = val; break; \
|
||||
case 4: *(unsigned int *)p = val; break; \
|
||||
case 8: *(unsigned long long *)p = val; break; \
|
||||
} \
|
||||
})
|
||||
|
||||
/* Differentiator between compilers builtin implementations. This is a
|
||||
* requirement due to the compiler parsing differences where GCC optimizes
|
||||
* early in parsing those constructs of type pointers to the builtin specific
|
||||
* type, resulting in not being possible to collect the required type
|
||||
* information in the builtin expansion.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define ___bpf_typeof(type) ((typeof(type) *) 0)
|
||||
#else
|
||||
#define ___bpf_typeof1(type, NR) ({ \
|
||||
extern typeof(type) *___concat(bpf_type_tmp_, NR); \
|
||||
___concat(bpf_type_tmp_, NR); \
|
||||
})
|
||||
#define ___bpf_typeof(type) ___bpf_typeof1(type, __COUNTER__)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#define ___bpf_field_ref1(field) (field)
|
||||
#define ___bpf_field_ref2(type, field) (___bpf_typeof(type)->field)
|
||||
#else
|
||||
#define ___bpf_field_ref1(field) (&(field))
|
||||
#define ___bpf_field_ref2(type, field) (&(___bpf_typeof(type)->field))
|
||||
#endif
|
||||
#define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field)
|
||||
#define ___bpf_field_ref(args...) \
|
||||
___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args)
|
||||
|
||||
@@ -218,7 +162,7 @@ enum bpf_enum_value_kind {
|
||||
* BTF. Always succeeds.
|
||||
*/
|
||||
#define bpf_core_type_id_local(type) \
|
||||
__builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_LOCAL)
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)
|
||||
|
||||
/*
|
||||
* Convenience macro to get BTF type ID of a target kernel's type that matches
|
||||
@@ -228,7 +172,7 @@ enum bpf_enum_value_kind {
|
||||
* - 0, if no matching type was found in a target kernel BTF.
|
||||
*/
|
||||
#define bpf_core_type_id_kernel(type) \
|
||||
__builtin_btf_type_id(*___bpf_typeof(type), BPF_TYPE_ID_TARGET)
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided named type
|
||||
@@ -238,7 +182,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_exists(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_EXISTS)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided named type
|
||||
@@ -248,7 +192,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if the type does not match any in the target kernel
|
||||
*/
|
||||
#define bpf_core_type_matches(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_MATCHES)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES)
|
||||
|
||||
/*
|
||||
* Convenience macro to get the byte size of a provided named type
|
||||
@@ -258,7 +202,7 @@ enum bpf_enum_value_kind {
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_size(type) \
|
||||
__builtin_preserve_type_info(*___bpf_typeof(type), BPF_TYPE_SIZE)
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided enumerator value is defined in
|
||||
@@ -268,13 +212,8 @@ enum bpf_enum_value_kind {
|
||||
* kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define bpf_core_enum_value_exists(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)
|
||||
#else
|
||||
#define bpf_core_enum_value_exists(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_EXISTS)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convenience macro to get the integer value of an enumerator value in
|
||||
@@ -284,13 +223,8 @@ enum bpf_enum_value_kind {
|
||||
* present in target kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#define bpf_core_enum_value(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)
|
||||
#else
|
||||
#define bpf_core_enum_value(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(___bpf_typeof(enum_type), enum_value, BPF_ENUMVAL_VALUE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures
|
||||
@@ -302,7 +236,7 @@ enum bpf_enum_value_kind {
|
||||
* a relocation, which records BTF type ID describing root struct/union and an
|
||||
* accessor string which describes exact embedded field that was used to take
|
||||
* an address. See detailed description of this relocation format and
|
||||
* semantics in comments to struct bpf_core_relo in include/uapi/linux/bpf.h.
|
||||
* semantics in comments to struct bpf_field_reloc in libbpf_internal.h.
|
||||
*
|
||||
* This relocation allows libbpf to adjust BPF instruction to use correct
|
||||
* actual field offset, based on target kernel BTF type that matches original
|
||||
@@ -326,17 +260,6 @@ enum bpf_enum_value_kind {
|
||||
#define bpf_core_read_user_str(dst, sz, src) \
|
||||
bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak;
|
||||
|
||||
/*
|
||||
* Cast provided pointer *ptr* into a pointer to a specified *type* in such
|
||||
* a way that BPF verifier will become aware of associated kernel-side BTF
|
||||
* type. This allows to access members of kernel types directly without the
|
||||
* need to use BPF_CORE_READ() macros.
|
||||
*/
|
||||
#define bpf_core_cast(ptr, type) \
|
||||
((typeof(type) *)bpf_rdonly_cast((ptr), bpf_core_type_id_kernel(type)))
|
||||
|
||||
#define ___concat(a, b) a ## b
|
||||
#define ___apply(fn, n) ___concat(fn, n)
|
||||
#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N
|
||||
@@ -388,13 +311,7 @@ extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak;
|
||||
#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__)
|
||||
|
||||
#if defined(__clang__) && (__clang_major__ >= 19)
|
||||
#define ___type(...) __typeof_unqual__(___arrow(__VA_ARGS__))
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 14)
|
||||
#define ___type(...) __typeof_unqual__(___arrow(__VA_ARGS__))
|
||||
#else
|
||||
#define ___type(...) typeof(___arrow(__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#define ___read(read_fn, dst, src_type, src, accessor) \
|
||||
read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
|
||||
@@ -447,7 +364,7 @@ extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak;
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ_INTO() */
|
||||
#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read_kernel, bpf_probe_read_kernel, \
|
||||
___core_read(bpf_probe_read, bpf_probe_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
@@ -483,7 +400,7 @@ extern void *bpf_rdonly_cast(const void *obj, __u32 btf_id) __ksym __weak;
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */
|
||||
#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read_kernel_str, bpf_probe_read_kernel, \
|
||||
___core_read(bpf_probe_read_str, bpf_probe_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ struct ksym_relo_desc {
|
||||
int insn_idx;
|
||||
bool is_weak;
|
||||
bool is_typeless;
|
||||
bool is_ld64;
|
||||
};
|
||||
|
||||
struct ksym_desc {
|
||||
@@ -25,7 +24,6 @@ struct ksym_desc {
|
||||
bool typeless;
|
||||
};
|
||||
int insn;
|
||||
bool is_ld64;
|
||||
};
|
||||
|
||||
struct bpf_gen {
|
||||
@@ -34,7 +32,6 @@ struct bpf_gen {
|
||||
void *data_cur;
|
||||
void *insn_start;
|
||||
void *insn_cur;
|
||||
bool swapped_endian;
|
||||
ssize_t cleanup_label;
|
||||
__u32 nr_progs;
|
||||
__u32 nr_maps;
|
||||
@@ -68,7 +65,7 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *value, __u
|
||||
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
|
||||
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
bool is_typeless, bool is_ld64, int kind, int insn_idx);
|
||||
bool is_typeless, int kind, int insn_idx);
|
||||
void bpf_gen__record_relo_core(struct bpf_gen *gen, const struct bpf_core_relo *core_relo);
|
||||
void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int key, int inner_map_idx);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,15 +13,6 @@
|
||||
#define __uint(name, val) int (*name)[val]
|
||||
#define __type(name, val) typeof(val) *name
|
||||
#define __array(name, val) typeof(val) *name[]
|
||||
#define __ulong(name, val) enum { ___bpf_concat(__unique_value, __COUNTER__) = val } name
|
||||
|
||||
#ifndef likely
|
||||
#define likely(x) (__builtin_expect(!!(x), 1))
|
||||
#endif
|
||||
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) (__builtin_expect(!!(x), 0))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro to place programs, maps, license in
|
||||
@@ -86,21 +77,16 @@
|
||||
/*
|
||||
* Helper macros to manipulate data structures
|
||||
*/
|
||||
|
||||
/* offsetof() definition that uses __builtin_offset() might not preserve field
|
||||
* offset CO-RE relocation properly, so force-redefine offsetof() using
|
||||
* old-school approach which works with CO-RE correctly
|
||||
*/
|
||||
#undef offsetof
|
||||
#define offsetof(type, member) ((unsigned long)&((type *)0)->member)
|
||||
|
||||
/* redefined container_of() to ensure we use the above offsetof() macro */
|
||||
#undef container_of
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
({ \
|
||||
void *__mptr = (void *)(ptr); \
|
||||
((type *)(__mptr - offsetof(type, member))); \
|
||||
})
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler (optimization) barrier.
|
||||
@@ -123,7 +109,7 @@
|
||||
* This is a variable-specific variant of more global barrier().
|
||||
*/
|
||||
#ifndef barrier_var
|
||||
#define barrier_var(var) asm volatile("" : "+r"(var))
|
||||
#define barrier_var(var) asm volatile("" : "=r"(var) : "0"(var))
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -145,8 +131,7 @@
|
||||
/*
|
||||
* Helper function to perform a tail call with a constant/immediate map slot.
|
||||
*/
|
||||
#if (defined(__clang__) && __clang_major__ >= 8) || (!defined(__clang__) && __GNUC__ > 12)
|
||||
#if defined(__bpf__)
|
||||
#if __clang_major__ >= 8 && defined(__bpf__)
|
||||
static __always_inline void
|
||||
bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
|
||||
{
|
||||
@@ -174,7 +159,6 @@ bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum libbpf_pin_type {
|
||||
LIBBPF_PIN_NONE,
|
||||
@@ -190,32 +174,8 @@ enum libbpf_tristate {
|
||||
|
||||
#define __kconfig __attribute__((section(".kconfig")))
|
||||
#define __ksym __attribute__((section(".ksyms")))
|
||||
#define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
|
||||
#define __kptr __attribute__((btf_type_tag("kptr")))
|
||||
#define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr")))
|
||||
#define __uptr __attribute__((btf_type_tag("uptr")))
|
||||
|
||||
#if defined (__clang__)
|
||||
#define bpf_ksym_exists(sym) ({ \
|
||||
_Static_assert(!__builtin_constant_p(!!sym), \
|
||||
#sym " should be marked as __weak"); \
|
||||
!!sym; \
|
||||
})
|
||||
#elif __GNUC__ > 8
|
||||
#define bpf_ksym_exists(sym) ({ \
|
||||
_Static_assert(__builtin_has_attribute (*sym, __weak__), \
|
||||
#sym " should be marked as __weak"); \
|
||||
!!sym; \
|
||||
})
|
||||
#else
|
||||
#define bpf_ksym_exists(sym) !!sym
|
||||
#endif
|
||||
|
||||
#define __arg_ctx __attribute__((btf_decl_tag("arg:ctx")))
|
||||
#define __arg_nonnull __attribute((btf_decl_tag("arg:nonnull")))
|
||||
#define __arg_nullable __attribute((btf_decl_tag("arg:nullable")))
|
||||
#define __arg_trusted __attribute((btf_decl_tag("arg:trusted")))
|
||||
#define __arg_arena __attribute((btf_decl_tag("arg:arena")))
|
||||
#define __kptr_ref __attribute__((btf_type_tag("kptr_ref")))
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
@@ -326,107 +286,4 @@ enum libbpf_tristate {
|
||||
/* Helper macro to print out debug messages */
|
||||
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
|
||||
|
||||
struct bpf_iter_num;
|
||||
|
||||
extern int bpf_iter_num_new(struct bpf_iter_num *it, int start, int end) __weak __ksym;
|
||||
extern int *bpf_iter_num_next(struct bpf_iter_num *it) __weak __ksym;
|
||||
extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
|
||||
|
||||
#ifndef bpf_for_each
|
||||
/* bpf_for_each(iter_type, cur_elem, args...) provides generic construct for
|
||||
* using BPF open-coded iterators without having to write mundane explicit
|
||||
* low-level loop logic. Instead, it provides for()-like generic construct
|
||||
* that can be used pretty naturally. E.g., for some hypothetical cgroup
|
||||
* iterator, you'd write:
|
||||
*
|
||||
* struct cgroup *cg, *parent_cg = <...>;
|
||||
*
|
||||
* bpf_for_each(cgroup, cg, parent_cg, CG_ITER_CHILDREN) {
|
||||
* bpf_printk("Child cgroup id = %d", cg->cgroup_id);
|
||||
* if (cg->cgroup_id == 123)
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* I.e., it looks almost like high-level for each loop in other languages,
|
||||
* supports continue/break, and is verifiable by BPF verifier.
|
||||
*
|
||||
* For iterating integers, the difference between bpf_for_each(num, i, N, M)
|
||||
* and bpf_for(i, N, M) is in that bpf_for() provides additional proof to
|
||||
* verifier that i is in [N, M) range, and in bpf_for_each() case i is `int
|
||||
* *`, not just `int`. So for integers bpf_for() is more convenient.
|
||||
*
|
||||
* Note: this macro relies on C99 feature of allowing to declare variables
|
||||
* inside for() loop, bound to for() loop lifetime. It also utilizes GCC
|
||||
* extension: __attribute__((cleanup(<func>))), supported by both GCC and
|
||||
* Clang.
|
||||
*/
|
||||
#define bpf_for_each(type, cur, args...) for ( \
|
||||
/* initialize and define destructor */ \
|
||||
struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */, \
|
||||
cleanup(bpf_iter_##type##_destroy))), \
|
||||
/* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */ \
|
||||
*___p __attribute__((unused)) = ( \
|
||||
bpf_iter_##type##_new(&___it, ##args), \
|
||||
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||
/* for bpf_iter_##type##_destroy() when used from cleanup() attribute */ \
|
||||
(void)bpf_iter_##type##_destroy, (void *)0); \
|
||||
/* iteration and termination check */ \
|
||||
(((cur) = bpf_iter_##type##_next(&___it))); \
|
||||
)
|
||||
#endif /* bpf_for_each */
|
||||
|
||||
#ifndef bpf_for
|
||||
/* bpf_for(i, start, end) implements a for()-like looping construct that sets
|
||||
* provided integer variable *i* to values starting from *start* through,
|
||||
* but not including, *end*. It also proves to BPF verifier that *i* belongs
|
||||
* to range [start, end), so this can be used for accessing arrays without
|
||||
* extra checks.
|
||||
*
|
||||
* Note: *start* and *end* are assumed to be expressions with no side effects
|
||||
* and whose values do not change throughout bpf_for() loop execution. They do
|
||||
* not have to be statically known or constant, though.
|
||||
*
|
||||
* Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
|
||||
* loop bound variables and cleanup attribute, supported by GCC and Clang.
|
||||
*/
|
||||
#define bpf_for(i, start, end) for ( \
|
||||
/* initialize and define destructor */ \
|
||||
struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \
|
||||
cleanup(bpf_iter_num_destroy))), \
|
||||
/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \
|
||||
*___p __attribute__((unused)) = ( \
|
||||
bpf_iter_num_new(&___it, (start), (end)), \
|
||||
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||
/* for bpf_iter_num_destroy() when used from cleanup() attribute */ \
|
||||
(void)bpf_iter_num_destroy, (void *)0); \
|
||||
({ \
|
||||
/* iteration step */ \
|
||||
int *___t = bpf_iter_num_next(&___it); \
|
||||
/* termination and bounds check */ \
|
||||
(___t && ((i) = *___t, (i) >= (start) && (i) < (end))); \
|
||||
}); \
|
||||
)
|
||||
#endif /* bpf_for */
|
||||
|
||||
#ifndef bpf_repeat
|
||||
/* bpf_repeat(N) performs N iterations without exposing iteration number
|
||||
*
|
||||
* Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()
|
||||
* loop bound variables and cleanup attribute, supported by GCC and Clang.
|
||||
*/
|
||||
#define bpf_repeat(N) for ( \
|
||||
/* initialize and define destructor */ \
|
||||
struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \
|
||||
cleanup(bpf_iter_num_destroy))), \
|
||||
/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \
|
||||
*___p __attribute__((unused)) = ( \
|
||||
bpf_iter_num_new(&___it, 0, (N)), \
|
||||
/* this is a workaround for Clang bug: it currently doesn't emit BTF */ \
|
||||
/* for bpf_iter_num_destroy() when used from cleanup() attribute */ \
|
||||
(void)bpf_iter_num_destroy, (void *)0); \
|
||||
bpf_iter_num_next(&___it); \
|
||||
/* nothing here */ \
|
||||
)
|
||||
#endif /* bpf_repeat */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#ifndef __BPF_TRACING_H__
|
||||
#define __BPF_TRACING_H__
|
||||
|
||||
#include "bpf_helpers.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
||||
#if defined(__TARGET_ARCH_x86)
|
||||
@@ -32,9 +32,6 @@
|
||||
#elif defined(__TARGET_ARCH_arc)
|
||||
#define bpf_target_arc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_loongarch)
|
||||
#define bpf_target_loongarch
|
||||
#define bpf_target_defined
|
||||
#else
|
||||
|
||||
/* Fall back to what the compiler says */
|
||||
@@ -65,9 +62,6 @@
|
||||
#elif defined(__arc__)
|
||||
#define bpf_target_arc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__loongarch__)
|
||||
#define bpf_target_loongarch
|
||||
#define bpf_target_defined
|
||||
#endif /* no compiler target */
|
||||
|
||||
#endif
|
||||
@@ -78,10 +72,6 @@
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
/*
|
||||
* https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI
|
||||
*/
|
||||
|
||||
#if defined(__KERNEL__) || defined(__VMLINUX_H__)
|
||||
|
||||
#define __PT_PARM1_REG di
|
||||
@@ -89,40 +79,25 @@
|
||||
#define __PT_PARM3_REG dx
|
||||
#define __PT_PARM4_REG cx
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_PARM6_REG r9
|
||||
/*
|
||||
* Syscall uses r10 for PARM4. See arch/x86/entry/entry_64.S:entry_SYSCALL_64
|
||||
* comments in Linux sources. And refer to syscall(2) manpage.
|
||||
*/
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG r10
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
|
||||
#define __PT_RET_REG sp
|
||||
#define __PT_FP_REG bp
|
||||
#define __PT_RC_REG ax
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG ip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
/* i386 kernel is built with -mregparm=3 */
|
||||
#define __PT_PARM1_REG eax
|
||||
#define __PT_PARM2_REG edx
|
||||
#define __PT_PARM3_REG ecx
|
||||
/* i386 syscall ABI is very different, refer to syscall(2) manpage */
|
||||
#define __PT_PARM1_SYSCALL_REG ebx
|
||||
#define __PT_PARM2_SYSCALL_REG ecx
|
||||
#define __PT_PARM3_SYSCALL_REG edx
|
||||
#define __PT_PARM4_SYSCALL_REG esi
|
||||
#define __PT_PARM5_SYSCALL_REG edi
|
||||
#define __PT_PARM6_SYSCALL_REG ebp
|
||||
|
||||
/* i386 kernel is built with -mregparm=3 */
|
||||
#define __PT_PARM4_REG __unsupported__
|
||||
#define __PT_PARM5_REG __unsupported__
|
||||
#define __PT_RET_REG esp
|
||||
#define __PT_FP_REG ebp
|
||||
#define __PT_RC_REG eax
|
||||
@@ -136,20 +111,14 @@
|
||||
#define __PT_PARM3_REG rdx
|
||||
#define __PT_PARM4_REG rcx
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_PARM6_REG r9
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG r10
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
|
||||
#define __PT_RET_REG rsp
|
||||
#define __PT_FP_REG rbp
|
||||
#define __PT_RC_REG rax
|
||||
#define __PT_SP_REG rsp
|
||||
#define __PT_IP_REG rip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
@@ -157,13 +126,9 @@
|
||||
|
||||
#elif defined(bpf_target_s390)
|
||||
|
||||
/*
|
||||
* https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf
|
||||
*/
|
||||
|
||||
struct pt_regs___s390 {
|
||||
unsigned long orig_gpr2;
|
||||
} __attribute__((preserve_access_index));
|
||||
};
|
||||
|
||||
/* s390 provides user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const user_pt_regs *)(x))
|
||||
@@ -172,42 +137,21 @@ struct pt_regs___s390 {
|
||||
#define __PT_PARM3_REG gprs[4]
|
||||
#define __PT_PARM4_REG gprs[5]
|
||||
#define __PT_PARM5_REG gprs[6]
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG orig_gpr2
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG gprs[7]
|
||||
#define PT_REGS_PARM1_SYSCALL(x) (((const struct pt_regs___s390 *)(x))->__PT_PARM1_SYSCALL_REG)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||
BPF_CORE_READ((const struct pt_regs___s390 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||
|
||||
#define __PT_RET_REG gprs[14]
|
||||
#define __PT_RET_REG grps[14]
|
||||
#define __PT_FP_REG gprs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG gprs[2]
|
||||
#define __PT_SP_REG gprs[15]
|
||||
#define __PT_IP_REG psw.addr
|
||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___s390 *)(x), orig_gpr2)
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
/*
|
||||
* https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers
|
||||
*/
|
||||
|
||||
#define __PT_PARM1_REG uregs[0]
|
||||
#define __PT_PARM2_REG uregs[1]
|
||||
#define __PT_PARM3_REG uregs[2]
|
||||
#define __PT_PARM4_REG uregs[3]
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG uregs[4]
|
||||
#define __PT_PARM6_SYSCALL_REG uregs[5]
|
||||
#define __PT_PARM7_SYSCALL_REG uregs[6]
|
||||
|
||||
#define __PT_PARM5_REG uregs[4]
|
||||
#define __PT_RET_REG uregs[14]
|
||||
#define __PT_FP_REG uregs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG uregs[0]
|
||||
@@ -216,13 +160,9 @@ struct pt_regs___s390 {
|
||||
|
||||
#elif defined(bpf_target_arm64)
|
||||
|
||||
/*
|
||||
* https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers
|
||||
*/
|
||||
|
||||
struct pt_regs___arm64 {
|
||||
unsigned long orig_x0;
|
||||
} __attribute__((preserve_access_index));
|
||||
};
|
||||
|
||||
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))
|
||||
@@ -231,49 +171,21 @@ struct pt_regs___arm64 {
|
||||
#define __PT_PARM3_REG regs[2]
|
||||
#define __PT_PARM4_REG regs[3]
|
||||
#define __PT_PARM5_REG regs[4]
|
||||
#define __PT_PARM6_REG regs[5]
|
||||
#define __PT_PARM7_REG regs[6]
|
||||
#define __PT_PARM8_REG regs[7]
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG orig_x0
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
#define PT_REGS_PARM1_SYSCALL(x) (((const struct pt_regs___arm64 *)(x))->__PT_PARM1_SYSCALL_REG)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||
BPF_CORE_READ((const struct pt_regs___arm64 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||
|
||||
#define __PT_RET_REG regs[30]
|
||||
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG regs[0]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG pc
|
||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___arm64 *)(x), orig_x0)
|
||||
|
||||
#elif defined(bpf_target_mips)
|
||||
|
||||
/*
|
||||
* N64 ABI is assumed right now.
|
||||
* https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions
|
||||
*/
|
||||
|
||||
#define __PT_PARM1_REG regs[4]
|
||||
#define __PT_PARM2_REG regs[5]
|
||||
#define __PT_PARM3_REG regs[6]
|
||||
#define __PT_PARM4_REG regs[7]
|
||||
#define __PT_PARM5_REG regs[8]
|
||||
#define __PT_PARM6_REG regs[9]
|
||||
#define __PT_PARM7_REG regs[10]
|
||||
#define __PT_PARM8_REG regs[11]
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG /* only N32/N64 */
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG /* only N32/N64 */
|
||||
|
||||
#define __PT_RET_REG regs[31]
|
||||
#define __PT_FP_REG regs[30] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG regs[2]
|
||||
@@ -282,58 +194,26 @@ struct pt_regs___arm64 {
|
||||
|
||||
#elif defined(bpf_target_powerpc)
|
||||
|
||||
/*
|
||||
* http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf (page 3-14,
|
||||
* section "Function Calling Sequence")
|
||||
*/
|
||||
|
||||
#define __PT_PARM1_REG gpr[3]
|
||||
#define __PT_PARM2_REG gpr[4]
|
||||
#define __PT_PARM3_REG gpr[5]
|
||||
#define __PT_PARM4_REG gpr[6]
|
||||
#define __PT_PARM5_REG gpr[7]
|
||||
#define __PT_PARM6_REG gpr[8]
|
||||
#define __PT_PARM7_REG gpr[9]
|
||||
#define __PT_PARM8_REG gpr[10]
|
||||
|
||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
#define __PT_PARM1_SYSCALL_REG orig_gpr3
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
#if !defined(__arch64__)
|
||||
#define __PT_PARM7_SYSCALL_REG __PT_PARM7_REG /* only powerpc (not powerpc64) */
|
||||
#endif
|
||||
|
||||
#define __PT_RET_REG regs[31]
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG gpr[3]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG nip
|
||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#elif defined(bpf_target_sparc)
|
||||
|
||||
/*
|
||||
* https://en.wikipedia.org/wiki/Calling_convention#SPARC
|
||||
*/
|
||||
|
||||
#define __PT_PARM1_REG u_regs[UREG_I0]
|
||||
#define __PT_PARM2_REG u_regs[UREG_I1]
|
||||
#define __PT_PARM3_REG u_regs[UREG_I2]
|
||||
#define __PT_PARM4_REG u_regs[UREG_I3]
|
||||
#define __PT_PARM5_REG u_regs[UREG_I4]
|
||||
#define __PT_PARM6_REG u_regs[UREG_I5]
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
|
||||
#define __PT_RET_REG u_regs[UREG_I7]
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG u_regs[UREG_I0]
|
||||
@@ -347,106 +227,36 @@ struct pt_regs___arm64 {
|
||||
|
||||
#elif defined(bpf_target_riscv)
|
||||
|
||||
/*
|
||||
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions
|
||||
*/
|
||||
|
||||
struct pt_regs___riscv {
|
||||
unsigned long orig_a0;
|
||||
} __attribute__((preserve_access_index));
|
||||
|
||||
/* riscv provides struct user_regs_struct instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||
#define __PT_PARM1_REG a0
|
||||
#define __PT_PARM2_REG a1
|
||||
#define __PT_PARM3_REG a2
|
||||
#define __PT_PARM4_REG a3
|
||||
#define __PT_PARM5_REG a4
|
||||
#define __PT_PARM6_REG a5
|
||||
#define __PT_PARM7_REG a6
|
||||
#define __PT_PARM8_REG a7
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG orig_a0
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
#define PT_REGS_PARM1_SYSCALL(x) (((const struct pt_regs___riscv *)(x))->__PT_PARM1_SYSCALL_REG)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||
BPF_CORE_READ((const struct pt_regs___riscv *)(x), __PT_PARM1_SYSCALL_REG)
|
||||
|
||||
#define __PT_RET_REG ra
|
||||
#define __PT_FP_REG s0
|
||||
#define __PT_RC_REG a0
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG pc
|
||||
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#elif defined(bpf_target_arc)
|
||||
|
||||
/*
|
||||
* Section "Function Calling Sequence" (page 24):
|
||||
* https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf
|
||||
*/
|
||||
|
||||
/* arc provides struct user_regs_struct instead of struct pt_regs to userspace */
|
||||
/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||
#define __PT_PARM1_REG scratch.r0
|
||||
#define __PT_PARM2_REG scratch.r1
|
||||
#define __PT_PARM3_REG scratch.r2
|
||||
#define __PT_PARM4_REG scratch.r3
|
||||
#define __PT_PARM5_REG scratch.r4
|
||||
#define __PT_PARM6_REG scratch.r5
|
||||
#define __PT_PARM7_REG scratch.r6
|
||||
#define __PT_PARM8_REG scratch.r7
|
||||
|
||||
/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
|
||||
#define __PT_RET_REG scratch.blink
|
||||
#define __PT_FP_REG scratch.fp
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG scratch.r0
|
||||
#define __PT_SP_REG scratch.sp
|
||||
#define __PT_IP_REG scratch.ret
|
||||
|
||||
#elif defined(bpf_target_loongarch)
|
||||
|
||||
/*
|
||||
* https://docs.kernel.org/loongarch/introduction.html
|
||||
* https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
|
||||
*/
|
||||
|
||||
/* loongarch provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))
|
||||
#define __PT_PARM1_REG regs[4]
|
||||
#define __PT_PARM2_REG regs[5]
|
||||
#define __PT_PARM3_REG regs[6]
|
||||
#define __PT_PARM4_REG regs[7]
|
||||
#define __PT_PARM5_REG regs[8]
|
||||
#define __PT_PARM6_REG regs[9]
|
||||
#define __PT_PARM7_REG regs[10]
|
||||
#define __PT_PARM8_REG regs[11]
|
||||
|
||||
/* loongarch does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG
|
||||
#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG
|
||||
#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG
|
||||
#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG
|
||||
#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG
|
||||
#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG
|
||||
|
||||
#define __PT_RET_REG regs[1]
|
||||
#define __PT_FP_REG regs[22]
|
||||
#define __PT_RC_REG regs[4]
|
||||
#define __PT_SP_REG regs[3]
|
||||
#define __PT_IP_REG csr_era
|
||||
|
||||
#endif
|
||||
|
||||
@@ -454,49 +264,16 @@ struct pt_regs___riscv {
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
/* allow some architectures to override `struct pt_regs` */
|
||||
/* allow some architecutres to override `struct pt_regs` */
|
||||
#ifndef __PT_REGS_CAST
|
||||
#define __PT_REGS_CAST(x) (x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Different architectures support different number of arguments passed
|
||||
* through registers. i386 supports just 3, some arches support up to 8.
|
||||
*/
|
||||
#ifndef __PT_PARM4_REG
|
||||
#define __PT_PARM4_REG __unsupported__
|
||||
#endif
|
||||
#ifndef __PT_PARM5_REG
|
||||
#define __PT_PARM5_REG __unsupported__
|
||||
#endif
|
||||
#ifndef __PT_PARM6_REG
|
||||
#define __PT_PARM6_REG __unsupported__
|
||||
#endif
|
||||
#ifndef __PT_PARM7_REG
|
||||
#define __PT_PARM7_REG __unsupported__
|
||||
#endif
|
||||
#ifndef __PT_PARM8_REG
|
||||
#define __PT_PARM8_REG __unsupported__
|
||||
#endif
|
||||
/*
|
||||
* Similarly, syscall-specific conventions might differ between function call
|
||||
* conventions within each architecture. All supported architectures pass
|
||||
* either 6 or 7 syscall arguments in registers.
|
||||
*
|
||||
* See syscall(2) manpage for succinct table with information on each arch.
|
||||
*/
|
||||
#ifndef __PT_PARM7_SYSCALL_REG
|
||||
#define __PT_PARM7_SYSCALL_REG __unsupported__
|
||||
#endif
|
||||
|
||||
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
||||
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
||||
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
||||
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
|
||||
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
||||
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)
|
||||
#define PT_REGS_PARM7(x) (__PT_REGS_CAST(x)->__PT_PARM7_REG)
|
||||
#define PT_REGS_PARM8(x) (__PT_REGS_CAST(x)->__PT_PARM8_REG)
|
||||
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
||||
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
||||
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
||||
@@ -508,9 +285,6 @@ struct pt_regs;
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG)
|
||||
#define PT_REGS_PARM6_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_REG)
|
||||
#define PT_REGS_PARM7_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_REG)
|
||||
#define PT_REGS_PARM8_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM8_REG)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG)
|
||||
@@ -522,7 +296,7 @@ struct pt_regs;
|
||||
#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) || defined(bpf_target_arm64)
|
||||
#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
|
||||
@@ -537,33 +311,24 @@ struct pt_regs;
|
||||
#endif
|
||||
|
||||
#ifndef PT_REGS_PARM1_SYSCALL
|
||||
#define PT_REGS_PARM1_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM1_SYSCALL_REG)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_SYSCALL_REG)
|
||||
#endif
|
||||
#ifndef PT_REGS_PARM2_SYSCALL
|
||||
#define PT_REGS_PARM2_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM2_SYSCALL_REG)
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_SYSCALL_REG)
|
||||
#endif
|
||||
#ifndef PT_REGS_PARM3_SYSCALL
|
||||
#define PT_REGS_PARM3_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM3_SYSCALL_REG)
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_SYSCALL_REG)
|
||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM2_SYSCALL(x) PT_REGS_PARM2(x)
|
||||
#define PT_REGS_PARM3_SYSCALL(x) PT_REGS_PARM3(x)
|
||||
#ifndef PT_REGS_PARM4_SYSCALL
|
||||
#define PT_REGS_PARM4_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM4_SYSCALL_REG)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_SYSCALL_REG)
|
||||
#define PT_REGS_PARM4_SYSCALL(x) PT_REGS_PARM4(x)
|
||||
#endif
|
||||
#ifndef PT_REGS_PARM5_SYSCALL
|
||||
#define PT_REGS_PARM5_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM5_SYSCALL_REG)
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_SYSCALL_REG)
|
||||
#define PT_REGS_PARM5_SYSCALL(x) PT_REGS_PARM5(x)
|
||||
|
||||
#ifndef PT_REGS_PARM1_CORE_SYSCALL
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) PT_REGS_PARM1_CORE(x)
|
||||
#endif
|
||||
#ifndef PT_REGS_PARM6_SYSCALL
|
||||
#define PT_REGS_PARM6_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM6_SYSCALL_REG)
|
||||
#define PT_REGS_PARM6_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_SYSCALL_REG)
|
||||
#endif
|
||||
#ifndef PT_REGS_PARM7_SYSCALL
|
||||
#define PT_REGS_PARM7_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM7_SYSCALL_REG)
|
||||
#define PT_REGS_PARM7_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_SYSCALL_REG)
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) PT_REGS_PARM2_CORE(x)
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) PT_REGS_PARM3_CORE(x)
|
||||
#ifndef PT_REGS_PARM4_CORE_SYSCALL
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) PT_REGS_PARM4_CORE(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) PT_REGS_PARM5_CORE(x)
|
||||
|
||||
#else /* defined(bpf_target_defined) */
|
||||
|
||||
@@ -572,9 +337,6 @@ struct pt_regs;
|
||||
#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM6(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM7(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM8(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
@@ -586,9 +348,6 @@ struct pt_regs;
|
||||
#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM6_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM7_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM8_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
@@ -603,16 +362,12 @@ struct pt_regs;
|
||||
#define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM6_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM7_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM6_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM7_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#endif /* defined(bpf_target_defined) */
|
||||
|
||||
@@ -640,25 +395,25 @@ struct pt_regs;
|
||||
#endif
|
||||
|
||||
#define ___bpf_ctx_cast0() ctx
|
||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), ctx[0]
|
||||
#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), ctx[1]
|
||||
#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), ctx[2]
|
||||
#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), ctx[3]
|
||||
#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), ctx[4]
|
||||
#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), ctx[5]
|
||||
#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), ctx[6]
|
||||
#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), ctx[7]
|
||||
#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), ctx[8]
|
||||
#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), ctx[9]
|
||||
#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), ctx[10]
|
||||
#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), ctx[11]
|
||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
||||
#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1]
|
||||
#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2]
|
||||
#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3]
|
||||
#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4]
|
||||
#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5]
|
||||
#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6]
|
||||
#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7]
|
||||
#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8]
|
||||
#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9]
|
||||
#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10]
|
||||
#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11]
|
||||
#define ___bpf_ctx_cast(args...) ___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and
|
||||
* similar kinds of BPF programs, that accept input arguments as a single
|
||||
* pointer to untyped u64 array, where each u64 can actually be a typed
|
||||
* pointer or integer of different size. Instead of requiring user to write
|
||||
* pointer or integer of different size. Instead of requring user to write
|
||||
* manual casts and work with array elements by index, BPF_PROG macro
|
||||
* allows user to declare a list of named and typed input arguments in the
|
||||
* same syntax as for normal C function. All the casting is hidden and
|
||||
@@ -793,14 +548,11 @@ ____##name(unsigned long long *ctx ___bpf_ctx_decl(args))
|
||||
struct pt_regs;
|
||||
|
||||
#define ___bpf_kprobe_args0() ctx
|
||||
#define ___bpf_kprobe_args1(x) ___bpf_kprobe_args0(), (unsigned long long)PT_REGS_PARM1(ctx)
|
||||
#define ___bpf_kprobe_args2(x, args...) ___bpf_kprobe_args1(args), (unsigned long long)PT_REGS_PARM2(ctx)
|
||||
#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (unsigned long long)PT_REGS_PARM3(ctx)
|
||||
#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (unsigned long long)PT_REGS_PARM4(ctx)
|
||||
#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (unsigned long long)PT_REGS_PARM5(ctx)
|
||||
#define ___bpf_kprobe_args6(x, args...) ___bpf_kprobe_args5(args), (unsigned long long)PT_REGS_PARM6(ctx)
|
||||
#define ___bpf_kprobe_args7(x, args...) ___bpf_kprobe_args6(args), (unsigned long long)PT_REGS_PARM7(ctx)
|
||||
#define ___bpf_kprobe_args8(x, args...) ___bpf_kprobe_args7(args), (unsigned long long)PT_REGS_PARM8(ctx)
|
||||
#define ___bpf_kprobe_args1(x) ___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)
|
||||
#define ___bpf_kprobe_args2(x, args...) ___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)
|
||||
#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
||||
#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
||||
#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
||||
#define ___bpf_kprobe_args(args...) ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
@@ -808,7 +560,7 @@ struct pt_regs;
|
||||
* tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific
|
||||
* low-level way of getting kprobe input arguments from struct pt_regs, and
|
||||
* provides a familiar typed and named function arguments syntax and
|
||||
* semantics of accessing kprobe input parameters.
|
||||
* semantics of accessing kprobe input paremeters.
|
||||
*
|
||||
* Original struct pt_regs* context is preserved as 'ctx' argument. This might
|
||||
* be necessary when using BPF helpers like bpf_perf_event_output().
|
||||
@@ -828,7 +580,7 @@ static __always_inline typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#define ___bpf_kretprobe_args0() ctx
|
||||
#define ___bpf_kretprobe_args1(x) ___bpf_kretprobe_args0(), (unsigned long long)PT_REGS_RC(ctx)
|
||||
#define ___bpf_kretprobe_args1(x) ___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)
|
||||
#define ___bpf_kretprobe_args(args...) ___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
@@ -852,24 +604,20 @@ static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
/* If kernel has CONFIG_ARCH_HAS_SYSCALL_WRAPPER, read pt_regs directly */
|
||||
#define ___bpf_syscall_args0() ctx
|
||||
#define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (unsigned long long)PT_REGS_PARM1_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (unsigned long long)PT_REGS_PARM2_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (unsigned long long)PT_REGS_PARM3_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (unsigned long long)PT_REGS_PARM4_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (unsigned long long)PT_REGS_PARM5_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args6(x, args...) ___bpf_syscall_args5(args), (unsigned long long)PT_REGS_PARM6_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args7(x, args...) ___bpf_syscall_args6(args), (unsigned long long)PT_REGS_PARM7_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args(args...) ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args)
|
||||
|
||||
/* If kernel doesn't have CONFIG_ARCH_HAS_SYSCALL_WRAPPER, we have to BPF_CORE_READ from pt_regs */
|
||||
#define ___bpf_syswrap_args0() ctx
|
||||
#define ___bpf_syswrap_args1(x) ___bpf_syswrap_args0(), (unsigned long long)PT_REGS_PARM1_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args2(x, args...) ___bpf_syswrap_args1(args), (unsigned long long)PT_REGS_PARM2_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args3(x, args...) ___bpf_syswrap_args2(args), (unsigned long long)PT_REGS_PARM3_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args4(x, args...) ___bpf_syswrap_args3(args), (unsigned long long)PT_REGS_PARM4_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args5(x, args...) ___bpf_syswrap_args4(args), (unsigned long long)PT_REGS_PARM5_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args6(x, args...) ___bpf_syswrap_args5(args), (unsigned long long)PT_REGS_PARM6_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args7(x, args...) ___bpf_syswrap_args6(args), (unsigned long long)PT_REGS_PARM7_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args1(x) ___bpf_syswrap_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args2(x, args...) ___bpf_syswrap_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args3(x, args...) ___bpf_syswrap_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args4(x, args...) ___bpf_syswrap_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args5(x, args...) ___bpf_syswrap_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syswrap_args(args...) ___bpf_apply(___bpf_syswrap_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
@@ -919,11 +667,4 @@ ____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#define BPF_KPROBE_SYSCALL BPF_KSYSCALL
|
||||
|
||||
/* BPF_UPROBE and BPF_URETPROBE are identical to BPF_KPROBE and BPF_KRETPROBE,
|
||||
* but are named way less confusingly for SEC("uprobe") and SEC("uretprobe")
|
||||
* use cases.
|
||||
*/
|
||||
#define BPF_UPROBE(name, args...) BPF_KPROBE(name, ##args)
|
||||
#define BPF_URETPROBE(name, args...) BPF_KRETPROBE(name, ##args)
|
||||
|
||||
#endif
|
||||
|
||||
44
src/btf.h
44
src/btf.h
@@ -18,7 +18,6 @@ extern "C" {
|
||||
|
||||
#define BTF_ELF_SEC ".BTF"
|
||||
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
||||
#define BTF_BASE_ELF_SEC ".BTF.base"
|
||||
#define MAPS_ELF_SEC ".maps"
|
||||
|
||||
struct btf;
|
||||
@@ -108,27 +107,6 @@ LIBBPF_API struct btf *btf__new_empty(void);
|
||||
*/
|
||||
LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf);
|
||||
|
||||
/**
|
||||
* @brief **btf__distill_base()** creates new versions of the split BTF
|
||||
* *src_btf* and its base BTF. The new base BTF will only contain the types
|
||||
* needed to improve robustness of the split BTF to small changes in base BTF.
|
||||
* When that split BTF is loaded against a (possibly changed) base, this
|
||||
* distilled base BTF will help update references to that (possibly changed)
|
||||
* base BTF.
|
||||
*
|
||||
* Both the new split and its associated new base BTF must be freed by
|
||||
* the caller.
|
||||
*
|
||||
* If successful, 0 is returned and **new_base_btf** and **new_split_btf**
|
||||
* will point at new base/split BTF. Both the new split and its associated
|
||||
* new base BTF must be freed by the caller.
|
||||
*
|
||||
* A negative value is returned on error and the thread-local `errno` variable
|
||||
* is set to the error code as well.
|
||||
*/
|
||||
LIBBPF_API int btf__distill_base(const struct btf *src_btf, struct btf **new_base_btf,
|
||||
struct btf **new_split_btf);
|
||||
|
||||
LIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext);
|
||||
LIBBPF_API struct btf *btf__parse_split(const char *path, struct btf *base_btf);
|
||||
LIBBPF_API struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext);
|
||||
@@ -167,9 +145,6 @@ LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_API struct btf_ext *btf_ext__new(const __u8 *data, __u32 size);
|
||||
LIBBPF_API void btf_ext__free(struct btf_ext *btf_ext);
|
||||
LIBBPF_API const void *btf_ext__raw_data(const struct btf_ext *btf_ext, __u32 *size);
|
||||
LIBBPF_API enum btf_endianness btf_ext__endianness(const struct btf_ext *btf_ext);
|
||||
LIBBPF_API int btf_ext__set_endianness(struct btf_ext *btf_ext,
|
||||
enum btf_endianness endian);
|
||||
|
||||
LIBBPF_API int btf__find_str(struct btf *btf, const char *s);
|
||||
LIBBPF_API int btf__add_str(struct btf *btf, const char *s);
|
||||
@@ -227,7 +202,6 @@ LIBBPF_API int btf__add_volatile(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_const(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_restrict(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id);
|
||||
LIBBPF_API int btf__add_type_attr(struct btf *btf, const char *value, int ref_type_id);
|
||||
|
||||
/* func and func_proto construction APIs */
|
||||
LIBBPF_API int btf__add_func(struct btf *btf, const char *name,
|
||||
@@ -244,8 +218,6 @@ LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,
|
||||
/* tag construction API */
|
||||
LIBBPF_API int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
int component_idx);
|
||||
LIBBPF_API int btf__add_decl_attr(struct btf *btf, const char *value, int ref_type_id,
|
||||
int component_idx);
|
||||
|
||||
struct btf_dedup_opts {
|
||||
size_t sz;
|
||||
@@ -259,20 +231,6 @@ struct btf_dedup_opts {
|
||||
|
||||
LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **btf__relocate()** will check the split BTF *btf* for references
|
||||
* to base BTF kinds, and verify those references are compatible with
|
||||
* *base_btf*; if they are, *btf* is adjusted such that is re-parented to
|
||||
* *base_btf* and type ids and strings are adjusted to accommodate this.
|
||||
*
|
||||
* If successful, 0 is returned and **btf** now has **base_btf** as its
|
||||
* base.
|
||||
*
|
||||
* A negative value is returned on error and the thread-local `errno` variable
|
||||
* is set to the error code as well.
|
||||
*/
|
||||
LIBBPF_API int btf__relocate(struct btf *btf, const struct btf *base_btf);
|
||||
|
||||
struct btf_dump;
|
||||
|
||||
struct btf_dump_opts {
|
||||
@@ -292,7 +250,7 @@ LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
||||
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 compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* optional field name for type declaration, e.g.:
|
||||
* - struct my_struct <FNAME>
|
||||
|
||||
288
src/btf_dump.c
288
src/btf_dump.c
@@ -13,7 +13,6 @@
|
||||
#include <ctype.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -21,7 +20,6 @@
|
||||
#include "hashmap.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "str_error.h"
|
||||
|
||||
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;
|
||||
@@ -119,14 +117,14 @@ struct btf_dump {
|
||||
struct btf_dump_data *typed_dump;
|
||||
};
|
||||
|
||||
static size_t str_hash_fn(long key, void *ctx)
|
||||
static size_t str_hash_fn(const void *key, void *ctx)
|
||||
{
|
||||
return str_hash((void *)key);
|
||||
return str_hash(key);
|
||||
}
|
||||
|
||||
static bool str_equal_fn(long a, long b, void *ctx)
|
||||
static bool str_equal_fn(const void *a, const void *b, void *ctx)
|
||||
{
|
||||
return strcmp((void *)a, (void *)b) == 0;
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
|
||||
@@ -221,17 +219,6 @@ static int btf_dump_resize(struct btf_dump *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btf_dump_free_names(struct hashmap *map)
|
||||
{
|
||||
size_t bkt;
|
||||
struct hashmap_entry *cur;
|
||||
|
||||
hashmap__for_each_entry(map, cur, bkt)
|
||||
free((void *)cur->pkey);
|
||||
|
||||
hashmap__free(map);
|
||||
}
|
||||
|
||||
void btf_dump__free(struct btf_dump *d)
|
||||
{
|
||||
int i;
|
||||
@@ -250,8 +237,8 @@ void btf_dump__free(struct btf_dump *d)
|
||||
free(d->cached_names);
|
||||
free(d->emit_queue);
|
||||
free(d->decl_stack);
|
||||
btf_dump_free_names(d->type_names);
|
||||
btf_dump_free_names(d->ident_names);
|
||||
hashmap__free(d->type_names);
|
||||
hashmap__free(d->ident_names);
|
||||
|
||||
free(d);
|
||||
}
|
||||
@@ -305,7 +292,7 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
||||
* 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 knowing whether given enum type was referenced from other type:
|
||||
* 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.
|
||||
*/
|
||||
@@ -835,9 +822,14 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
||||
const struct btf_type *t)
|
||||
{
|
||||
const struct btf_member *m;
|
||||
int max_align = 1, align, i, bit_sz;
|
||||
int align, i, bit_sz;
|
||||
__u16 vlen;
|
||||
|
||||
align = btf__align_of(btf, id);
|
||||
/* size of a non-packed struct has to be a multiple of its alignment*/
|
||||
if (align && t->size % align)
|
||||
return true;
|
||||
|
||||
m = btf_members(t);
|
||||
vlen = btf_vlen(t);
|
||||
/* all non-bitfield fields have to be naturally aligned */
|
||||
@@ -846,11 +838,8 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
||||
bit_sz = btf_member_bitfield_size(t, i);
|
||||
if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
|
||||
return true;
|
||||
max_align = max(align, max_align);
|
||||
}
|
||||
/* size of a non-packed struct has to be a multiple of its alignment */
|
||||
if (t->size % max_align != 0)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* if original struct was marked as packed, but its layout is
|
||||
* naturally aligned, we'll detect that it's not packed
|
||||
@@ -858,97 +847,44 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void btf_dump_emit_bit_padding(const struct btf_dump *d,
|
||||
int cur_off, int next_off, int next_align,
|
||||
bool in_bitfield, int lvl)
|
||||
static int chip_away_bits(int total, int at_most)
|
||||
{
|
||||
const struct {
|
||||
const char *name;
|
||||
int bits;
|
||||
} pads[] = {
|
||||
{"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8}
|
||||
};
|
||||
int new_off = 0, pad_bits = 0, bits, i;
|
||||
const char *pad_type = NULL;
|
||||
return total % at_most ? : at_most;
|
||||
}
|
||||
|
||||
if (cur_off >= next_off)
|
||||
return; /* no gap */
|
||||
static void btf_dump_emit_bit_padding(const struct btf_dump *d,
|
||||
int cur_off, int m_off, int m_bit_sz,
|
||||
int align, int lvl)
|
||||
{
|
||||
int off_diff = m_off - cur_off;
|
||||
int ptr_bits = d->ptr_sz * 8;
|
||||
|
||||
/* For filling out padding we want to take advantage of
|
||||
* natural alignment rules to minimize unnecessary explicit
|
||||
* padding. First, we find the largest type (among long, int,
|
||||
* short, or char) that can be used to force naturally aligned
|
||||
* boundary. Once determined, we'll use such type to fill in
|
||||
* the remaining padding gap. In some cases we can rely on
|
||||
* compiler filling some gaps, but sometimes we need to force
|
||||
* alignment to close natural alignment with markers like
|
||||
* `long: 0` (this is always the case for bitfields). Note
|
||||
* that even if struct itself has, let's say 4-byte alignment
|
||||
* (i.e., it only uses up to int-aligned types), using `long:
|
||||
* X;` explicit padding doesn't actually change struct's
|
||||
* overall alignment requirements, but compiler does take into
|
||||
* account that type's (long, in this example) natural
|
||||
* alignment requirements when adding implicit padding. We use
|
||||
* this fact heavily and don't worry about ruining correct
|
||||
* struct alignment requirement.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(pads); i++) {
|
||||
pad_bits = pads[i].bits;
|
||||
pad_type = pads[i].name;
|
||||
if (off_diff <= 0)
|
||||
/* no gap */
|
||||
return;
|
||||
if (m_bit_sz == 0 && off_diff < align * 8)
|
||||
/* natural padding will take care of a gap */
|
||||
return;
|
||||
|
||||
new_off = roundup(cur_off, pad_bits);
|
||||
if (new_off <= next_off)
|
||||
break;
|
||||
}
|
||||
while (off_diff > 0) {
|
||||
const char *pad_type;
|
||||
int pad_bits;
|
||||
|
||||
if (new_off > cur_off && new_off <= next_off) {
|
||||
/* We need explicit `<type>: 0` aligning mark if next
|
||||
* field is right on alignment offset and its
|
||||
* alignment requirement is less strict than <type>'s
|
||||
* alignment (so compiler won't naturally align to the
|
||||
* offset we expect), or if subsequent `<type>: X`,
|
||||
* will actually completely fit in the remaining hole,
|
||||
* making compiler basically ignore `<type>: X`
|
||||
* completely.
|
||||
*/
|
||||
if (in_bitfield ||
|
||||
(new_off == next_off && roundup(cur_off, next_align * 8) != new_off) ||
|
||||
(new_off != next_off && next_off - new_off <= new_off - cur_off))
|
||||
/* but for bitfields we'll emit explicit bit count */
|
||||
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type,
|
||||
in_bitfield ? new_off - cur_off : 0);
|
||||
cur_off = new_off;
|
||||
}
|
||||
|
||||
/* Now we know we start at naturally aligned offset for a chosen
|
||||
* padding type (long, int, short, or char), and so the rest is just
|
||||
* a straightforward filling of remaining padding gap with full
|
||||
* `<type>: sizeof(<type>);` markers, except for the last one, which
|
||||
* might need smaller than sizeof(<type>) padding.
|
||||
*/
|
||||
while (cur_off != next_off) {
|
||||
bits = min(next_off - cur_off, pad_bits);
|
||||
if (bits == pad_bits) {
|
||||
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
|
||||
cur_off += bits;
|
||||
continue;
|
||||
}
|
||||
/* For the remainder padding that doesn't cover entire
|
||||
* pad_type bit length, we pick the smallest necessary type.
|
||||
* This is pure aesthetics, we could have just used `long`,
|
||||
* but having smallest necessary one communicates better the
|
||||
* scale of the padding gap.
|
||||
*/
|
||||
for (i = ARRAY_SIZE(pads) - 1; i >= 0; i--) {
|
||||
pad_type = pads[i].name;
|
||||
pad_bits = pads[i].bits;
|
||||
if (pad_bits < bits)
|
||||
continue;
|
||||
|
||||
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, bits);
|
||||
cur_off += bits;
|
||||
break;
|
||||
if (ptr_bits > 32 && off_diff > 32) {
|
||||
pad_type = "long";
|
||||
pad_bits = chip_away_bits(off_diff, ptr_bits);
|
||||
} else if (off_diff > 16) {
|
||||
pad_type = "int";
|
||||
pad_bits = chip_away_bits(off_diff, 32);
|
||||
} else if (off_diff > 8) {
|
||||
pad_type = "short";
|
||||
pad_bits = chip_away_bits(off_diff, 16);
|
||||
} else {
|
||||
pad_type = "char";
|
||||
pad_bits = chip_away_bits(off_diff, 8);
|
||||
}
|
||||
btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
|
||||
off_diff -= pad_bits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,11 +904,9 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
||||
{
|
||||
const struct btf_member *m = btf_members(t);
|
||||
bool is_struct = btf_is_struct(t);
|
||||
bool packed, prev_bitfield = false;
|
||||
int align, i, off = 0;
|
||||
int align, i, packed, off = 0;
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
align = btf__align_of(d->btf, id);
|
||||
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
||||
|
||||
btf_dump_printf(d, "%s%s%s {",
|
||||
@@ -982,47 +916,37 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
||||
|
||||
for (i = 0; i < vlen; i++, m++) {
|
||||
const char *fname;
|
||||
int m_off, m_sz, m_align;
|
||||
bool in_bitfield;
|
||||
int m_off, m_sz;
|
||||
|
||||
fname = btf_name_of(d, m->name_off);
|
||||
m_sz = btf_member_bitfield_size(t, i);
|
||||
m_off = btf_member_bit_offset(t, i);
|
||||
m_align = packed ? 1 : btf__align_of(d->btf, m->type);
|
||||
align = packed ? 1 : btf__align_of(d->btf, m->type);
|
||||
|
||||
in_bitfield = prev_bitfield && m_sz != 0;
|
||||
|
||||
btf_dump_emit_bit_padding(d, off, m_off, m_align, in_bitfield, 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_emit_type_decl(d, m->type, fname, lvl + 1);
|
||||
|
||||
if (m_sz) {
|
||||
btf_dump_printf(d, ": %d", m_sz);
|
||||
off = m_off + m_sz;
|
||||
prev_bitfield = true;
|
||||
} else {
|
||||
m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
|
||||
off = m_off + m_sz * 8;
|
||||
prev_bitfield = false;
|
||||
}
|
||||
|
||||
btf_dump_printf(d, ";");
|
||||
}
|
||||
|
||||
/* pad at the end, if necessary */
|
||||
if (is_struct)
|
||||
btf_dump_emit_bit_padding(d, off, t->size * 8, align, false, lvl + 1);
|
||||
|
||||
/*
|
||||
* Keep `struct empty {}` on a single line,
|
||||
* only print newline when there are regular or padding fields.
|
||||
*/
|
||||
if (vlen || t->size) {
|
||||
btf_dump_printf(d, "\n");
|
||||
btf_dump_printf(d, "%s}", pfx(lvl));
|
||||
} else {
|
||||
btf_dump_printf(d, "}");
|
||||
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)
|
||||
btf_dump_printf(d, "\n");
|
||||
btf_dump_printf(d, "%s}", pfx(lvl));
|
||||
if (packed)
|
||||
btf_dump_printf(d, " __attribute__((packed))");
|
||||
}
|
||||
@@ -1134,43 +1058,6 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
||||
else
|
||||
btf_dump_emit_enum64_val(d, t, lvl, vlen);
|
||||
btf_dump_printf(d, "\n%s}", pfx(lvl));
|
||||
|
||||
/* special case enums with special sizes */
|
||||
if (t->size == 1) {
|
||||
/* one-byte enums can be forced with mode(byte) attribute */
|
||||
btf_dump_printf(d, " __attribute__((mode(byte)))");
|
||||
} else if (t->size == 8 && d->ptr_sz == 8) {
|
||||
/* enum can be 8-byte sized if one of the enumerator values
|
||||
* doesn't fit in 32-bit integer, or by adding mode(word)
|
||||
* attribute (but probably only on 64-bit architectures); do
|
||||
* our best here to try to satisfy the contract without adding
|
||||
* unnecessary attributes
|
||||
*/
|
||||
bool needs_word_mode;
|
||||
|
||||
if (btf_is_enum(t)) {
|
||||
/* enum can't represent 64-bit values, so we need word mode */
|
||||
needs_word_mode = true;
|
||||
} else {
|
||||
/* enum64 needs mode(word) if none of its values has
|
||||
* non-zero upper 32-bits (which means that all values
|
||||
* fit in 32-bit integers and won't cause compiler to
|
||||
* bump enum to be 64-bit naturally
|
||||
*/
|
||||
int i;
|
||||
|
||||
needs_word_mode = true;
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (btf_enum64(t)[i].val_hi32 != 0) {
|
||||
needs_word_mode = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needs_word_mode)
|
||||
btf_dump_printf(d, " __attribute__((mode(word)))");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
||||
@@ -1305,7 +1192,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
* chain, restore stack, emit warning, and try to
|
||||
* proceed nevertheless
|
||||
*/
|
||||
pr_warn("not enough memory for decl stack: %s\n", errstr(err));
|
||||
pr_warn("not enough memory for decl stack:%d", err);
|
||||
d->decl_stack_cnt = stack_start;
|
||||
return;
|
||||
}
|
||||
@@ -1494,10 +1381,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
btf_dump_emit_mods(d, decls);
|
||||
name = btf_name_of(d, t->name_off);
|
||||
if (btf_kflag(t))
|
||||
btf_dump_printf(d, " __attribute__((%s))", name);
|
||||
else
|
||||
btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name);
|
||||
btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name);
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = btf_array(t);
|
||||
@@ -1563,12 +1447,10 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
* Clang for BPF target generates func_proto with no
|
||||
* args as a func_proto with a single void arg (e.g.,
|
||||
* `int (*f)(void)` vs just `int (*f)()`). We are
|
||||
* going to emit valid empty args (void) syntax for
|
||||
* such case. Similarly and conveniently, valid
|
||||
* no args case can be special-cased here as well.
|
||||
* going to pretend there are no args for such case.
|
||||
*/
|
||||
if (vlen == 0 || (vlen == 1 && p->type == 0)) {
|
||||
btf_dump_printf(d, "void)");
|
||||
if (vlen == 1 && p->type == 0) {
|
||||
btf_dump_printf(d, ")");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1638,22 +1520,11 @@ static void btf_dump_emit_type_cast(struct btf_dump *d, __u32 id,
|
||||
static size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
|
||||
const char *orig_name)
|
||||
{
|
||||
char *old_name, *new_name;
|
||||
size_t dup_cnt = 0;
|
||||
int err;
|
||||
|
||||
new_name = strdup(orig_name);
|
||||
if (!new_name)
|
||||
return 1;
|
||||
|
||||
(void)hashmap__find(name_map, orig_name, &dup_cnt);
|
||||
hashmap__find(name_map, orig_name, (void **)&dup_cnt);
|
||||
dup_cnt++;
|
||||
|
||||
err = hashmap__set(name_map, new_name, dup_cnt, &old_name, NULL);
|
||||
if (err)
|
||||
free(new_name);
|
||||
|
||||
free(old_name);
|
||||
hashmap__set(name_map, orig_name, (void *)dup_cnt, NULL, NULL);
|
||||
|
||||
return dup_cnt;
|
||||
}
|
||||
@@ -1935,7 +1806,6 @@ static int btf_dump_int_data(struct btf_dump *d,
|
||||
if (d->typed_dump->is_array_terminated)
|
||||
break;
|
||||
if (*(char *)data == '\0') {
|
||||
btf_dump_type_values(d, "'\\0'");
|
||||
d->typed_dump->is_array_terminated = true;
|
||||
break;
|
||||
}
|
||||
@@ -2038,7 +1908,6 @@ static int btf_dump_array_data(struct btf_dump *d,
|
||||
__u32 i, elem_type_id;
|
||||
__s64 elem_size;
|
||||
bool is_array_member;
|
||||
bool is_array_terminated;
|
||||
|
||||
elem_type_id = array->type;
|
||||
elem_type = skip_mods_and_typedefs(d->btf, elem_type_id, NULL);
|
||||
@@ -2074,15 +1943,12 @@ static int btf_dump_array_data(struct btf_dump *d,
|
||||
*/
|
||||
is_array_member = d->typed_dump->is_array_member;
|
||||
d->typed_dump->is_array_member = true;
|
||||
is_array_terminated = d->typed_dump->is_array_terminated;
|
||||
d->typed_dump->is_array_terminated = false;
|
||||
for (i = 0; i < array->nelems; i++, data += elem_size) {
|
||||
if (d->typed_dump->is_array_terminated)
|
||||
break;
|
||||
btf_dump_dump_type_data(d, NULL, elem_type, elem_type_id, data, 0, 0);
|
||||
}
|
||||
d->typed_dump->is_array_member = is_array_member;
|
||||
d->typed_dump->is_array_terminated = is_array_terminated;
|
||||
d->typed_dump->depth--;
|
||||
btf_dump_data_pfx(d);
|
||||
btf_dump_type_values(d, "]");
|
||||
@@ -2097,7 +1963,7 @@ static int btf_dump_struct_data(struct btf_dump *d,
|
||||
{
|
||||
const struct btf_member *m = btf_members(t);
|
||||
__u16 n = btf_vlen(t);
|
||||
int i, err = 0;
|
||||
int i, err;
|
||||
|
||||
/* note that we increment depth before calling btf_dump_print() below;
|
||||
* this is intentional. btf_dump_data_newline() will not print a
|
||||
@@ -2261,25 +2127,9 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
|
||||
const struct btf_type *t,
|
||||
__u32 id,
|
||||
const void *data,
|
||||
__u8 bits_offset,
|
||||
__u8 bit_sz)
|
||||
__u8 bits_offset)
|
||||
{
|
||||
__s64 size;
|
||||
|
||||
if (bit_sz) {
|
||||
/* bits_offset is at most 7. bit_sz is at most 128. */
|
||||
__u8 nr_bytes = (bits_offset + bit_sz + 7) / 8;
|
||||
|
||||
/* When bit_sz is non zero, it is called from
|
||||
* btf_dump_struct_data() where it only cares about
|
||||
* negative error value.
|
||||
* Return nr_bytes in success case to make it
|
||||
* consistent as the regular integer case below.
|
||||
*/
|
||||
return data + nr_bytes > d->typed_dump->data_end ? -E2BIG : nr_bytes;
|
||||
}
|
||||
|
||||
size = btf__resolve_size(d->btf, id);
|
||||
__s64 size = btf__resolve_size(d->btf, id);
|
||||
|
||||
if (size < 0 || size >= INT_MAX) {
|
||||
pr_warn("unexpected size [%zu] for id [%u]\n",
|
||||
@@ -2434,7 +2284,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
|
||||
{
|
||||
int size, err = 0;
|
||||
|
||||
size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset, bit_sz);
|
||||
size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset);
|
||||
if (size < 0)
|
||||
return size;
|
||||
err = btf_dump_type_data_check_zero(d, t, id, data, bits_offset, bit_sz);
|
||||
|
||||
177
src/btf_iter.c
177
src/btf_iter.c
@@ -1,177 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
/* Copyright (c) 2024, Oracle and/or its affiliates. */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/btf.h>
|
||||
|
||||
#define btf_var_secinfos(t) (struct btf_var_secinfo *)btf_type_var_secinfo(t)
|
||||
|
||||
#else
|
||||
#include "btf.h"
|
||||
#include "libbpf_internal.h"
|
||||
#endif
|
||||
|
||||
int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t,
|
||||
enum btf_field_iter_kind iter_kind)
|
||||
{
|
||||
it->p = NULL;
|
||||
it->m_idx = -1;
|
||||
it->off_idx = 0;
|
||||
it->vlen = 0;
|
||||
|
||||
switch (iter_kind) {
|
||||
case BTF_FIELD_ITER_IDS:
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_UNKN:
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_ENUM64:
|
||||
it->desc = (struct btf_field_desc) {};
|
||||
break;
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)} };
|
||||
break;
|
||||
case BTF_KIND_ARRAY:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
2, {sizeof(struct btf_type) + offsetof(struct btf_array, type),
|
||||
sizeof(struct btf_type) + offsetof(struct btf_array, index_type)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
0, {},
|
||||
sizeof(struct btf_member),
|
||||
1, {offsetof(struct btf_member, type)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, type)},
|
||||
sizeof(struct btf_param),
|
||||
1, {offsetof(struct btf_param, type)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_DATASEC:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
0, {},
|
||||
sizeof(struct btf_var_secinfo),
|
||||
1, {offsetof(struct btf_var_secinfo, type)}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case BTF_FIELD_ITER_STRS:
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_UNKN:
|
||||
it->desc = (struct btf_field_desc) {};
|
||||
break;
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_ARRAY:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
case BTF_KIND_DATASEC:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, name_off)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_ENUM:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, name_off)},
|
||||
sizeof(struct btf_enum),
|
||||
1, {offsetof(struct btf_enum, name_off)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_ENUM64:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, name_off)},
|
||||
sizeof(struct btf_enum64),
|
||||
1, {offsetof(struct btf_enum64, name_off)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, name_off)},
|
||||
sizeof(struct btf_member),
|
||||
1, {offsetof(struct btf_member, name_off)}
|
||||
};
|
||||
break;
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
it->desc = (struct btf_field_desc) {
|
||||
1, {offsetof(struct btf_type, name_off)},
|
||||
sizeof(struct btf_param),
|
||||
1, {offsetof(struct btf_param, name_off)}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (it->desc.m_sz)
|
||||
it->vlen = btf_vlen(t);
|
||||
|
||||
it->p = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u32 *btf_field_iter_next(struct btf_field_iter *it)
|
||||
{
|
||||
if (!it->p)
|
||||
return NULL;
|
||||
|
||||
if (it->m_idx < 0) {
|
||||
if (it->off_idx < it->desc.t_off_cnt)
|
||||
return it->p + it->desc.t_offs[it->off_idx++];
|
||||
/* move to per-member iteration */
|
||||
it->m_idx = 0;
|
||||
it->p += sizeof(struct btf_type);
|
||||
it->off_idx = 0;
|
||||
}
|
||||
|
||||
/* if type doesn't have members, stop */
|
||||
if (it->desc.m_sz == 0) {
|
||||
it->p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (it->off_idx >= it->desc.m_off_cnt) {
|
||||
/* exhausted this member's fields, go to the next member */
|
||||
it->m_idx++;
|
||||
it->p += it->desc.m_sz;
|
||||
it->off_idx = 0;
|
||||
}
|
||||
|
||||
if (it->m_idx < it->vlen)
|
||||
return it->p + it->desc.m_offs[it->off_idx++];
|
||||
|
||||
it->p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,519 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2024, Oracle and/or its affiliates. */
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/bpf_verifier.h>
|
||||
|
||||
#define btf_type_by_id (struct btf_type *)btf_type_by_id
|
||||
#define btf__type_cnt btf_nr_types
|
||||
#define btf__base_btf btf_base_btf
|
||||
#define btf__name_by_offset btf_name_by_offset
|
||||
#define btf__str_by_offset btf_str_by_offset
|
||||
#define btf_kflag btf_type_kflag
|
||||
|
||||
#define calloc(nmemb, sz) kvcalloc(nmemb, sz, GFP_KERNEL | __GFP_NOWARN)
|
||||
#define free(ptr) kvfree(ptr)
|
||||
#define qsort(base, num, sz, cmp) sort(base, num, sz, cmp, NULL)
|
||||
|
||||
#else
|
||||
|
||||
#include "btf.h"
|
||||
#include "bpf.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
struct btf;
|
||||
|
||||
struct btf_relocate {
|
||||
struct btf *btf;
|
||||
const struct btf *base_btf;
|
||||
const struct btf *dist_base_btf;
|
||||
unsigned int nr_base_types;
|
||||
unsigned int nr_split_types;
|
||||
unsigned int nr_dist_base_types;
|
||||
int dist_str_len;
|
||||
int base_str_len;
|
||||
__u32 *id_map;
|
||||
__u32 *str_map;
|
||||
};
|
||||
|
||||
/* Set temporarily in relocation id_map if distilled base struct/union is
|
||||
* embedded in a split BTF struct/union; in such a case, size information must
|
||||
* match between distilled base BTF and base BTF representation of type.
|
||||
*/
|
||||
#define BTF_IS_EMBEDDED ((__u32)-1)
|
||||
|
||||
/* <name, size, id> triple used in sorting/searching distilled base BTF. */
|
||||
struct btf_name_info {
|
||||
const char *name;
|
||||
/* set when search requires a size match */
|
||||
bool needs_size: 1;
|
||||
unsigned int size: 31;
|
||||
__u32 id;
|
||||
};
|
||||
|
||||
static int btf_relocate_rewrite_type_id(struct btf_relocate *r, __u32 i)
|
||||
{
|
||||
struct btf_type *t = btf_type_by_id(r->btf, i);
|
||||
struct btf_field_iter it;
|
||||
__u32 *id;
|
||||
int err;
|
||||
|
||||
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while ((id = btf_field_iter_next(&it)))
|
||||
*id = r->id_map[*id];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Simple string comparison used for sorting within BTF, since all distilled
|
||||
* types are named. If strings match, and size is non-zero for both elements
|
||||
* fall back to using size for ordering.
|
||||
*/
|
||||
static int cmp_btf_name_size(const void *n1, const void *n2)
|
||||
{
|
||||
const struct btf_name_info *ni1 = n1;
|
||||
const struct btf_name_info *ni2 = n2;
|
||||
int name_diff = strcmp(ni1->name, ni2->name);
|
||||
|
||||
if (!name_diff && ni1->needs_size && ni2->needs_size)
|
||||
return ni2->size - ni1->size;
|
||||
return name_diff;
|
||||
}
|
||||
|
||||
/* Binary search with a small twist; find leftmost element that matches
|
||||
* so that we can then iterate through all exact matches. So for example
|
||||
* searching { "a", "bb", "bb", "c" } we would always match on the
|
||||
* leftmost "bb".
|
||||
*/
|
||||
static struct btf_name_info *search_btf_name_size(struct btf_name_info *key,
|
||||
struct btf_name_info *vals,
|
||||
int nelems)
|
||||
{
|
||||
struct btf_name_info *ret = NULL;
|
||||
int high = nelems - 1;
|
||||
int low = 0;
|
||||
|
||||
while (low <= high) {
|
||||
int mid = (low + high)/2;
|
||||
struct btf_name_info *val = &vals[mid];
|
||||
int diff = cmp_btf_name_size(key, val);
|
||||
|
||||
if (diff == 0)
|
||||
ret = val;
|
||||
/* even if found, keep searching for leftmost match */
|
||||
if (diff <= 0)
|
||||
high = mid - 1;
|
||||
else
|
||||
low = mid + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If a member of a split BTF struct/union refers to a base BTF
|
||||
* struct/union, mark that struct/union id temporarily in the id_map
|
||||
* with BTF_IS_EMBEDDED. Members can be const/restrict/volatile/typedef
|
||||
* reference types, but if a pointer is encountered, the type is no longer
|
||||
* considered embedded.
|
||||
*/
|
||||
static int btf_mark_embedded_composite_type_ids(struct btf_relocate *r, __u32 i)
|
||||
{
|
||||
struct btf_type *t = btf_type_by_id(r->btf, i);
|
||||
struct btf_field_iter it;
|
||||
__u32 *id;
|
||||
int err;
|
||||
|
||||
if (!btf_is_composite(t))
|
||||
return 0;
|
||||
|
||||
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while ((id = btf_field_iter_next(&it))) {
|
||||
__u32 next_id = *id;
|
||||
|
||||
while (next_id) {
|
||||
t = btf_type_by_id(r->btf, next_id);
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
next_id = t->type;
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
struct btf_array *a = btf_array(t);
|
||||
|
||||
next_id = a->type;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
if (next_id < r->nr_dist_base_types)
|
||||
r->id_map[next_id] = BTF_IS_EMBEDDED;
|
||||
next_id = 0;
|
||||
break;
|
||||
default:
|
||||
next_id = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build a map from distilled base BTF ids to base BTF ids. To do so, iterate
|
||||
* through base BTF looking up distilled type (using binary search) equivalents.
|
||||
*/
|
||||
static int btf_relocate_map_distilled_base(struct btf_relocate *r)
|
||||
{
|
||||
struct btf_name_info *info, *info_end;
|
||||
struct btf_type *base_t, *dist_t;
|
||||
__u8 *base_name_cnt = NULL;
|
||||
int err = 0;
|
||||
__u32 id;
|
||||
|
||||
/* generate a sort index array of name/type ids sorted by name for
|
||||
* distilled base BTF to speed name-based lookups.
|
||||
*/
|
||||
info = calloc(r->nr_dist_base_types, sizeof(*info));
|
||||
if (!info) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
info_end = info + r->nr_dist_base_types;
|
||||
for (id = 0; id < r->nr_dist_base_types; id++) {
|
||||
dist_t = btf_type_by_id(r->dist_base_btf, id);
|
||||
info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
|
||||
info[id].id = id;
|
||||
info[id].size = dist_t->size;
|
||||
info[id].needs_size = true;
|
||||
}
|
||||
qsort(info, r->nr_dist_base_types, sizeof(*info), cmp_btf_name_size);
|
||||
|
||||
/* Mark distilled base struct/union members of split BTF structs/unions
|
||||
* in id_map with BTF_IS_EMBEDDED; this signals that these types
|
||||
* need to match both name and size, otherwise embedding the base
|
||||
* struct/union in the split type is invalid.
|
||||
*/
|
||||
for (id = r->nr_dist_base_types; id < r->nr_dist_base_types + r->nr_split_types; id++) {
|
||||
err = btf_mark_embedded_composite_type_ids(r, id);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Collect name counts for composite types in base BTF. If multiple
|
||||
* instances of a struct/union of the same name exist, we need to use
|
||||
* size to determine which to map to since name alone is ambiguous.
|
||||
*/
|
||||
base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt));
|
||||
if (!base_name_cnt) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
for (id = 1; id < r->nr_base_types; id++) {
|
||||
base_t = btf_type_by_id(r->base_btf, id);
|
||||
if (!btf_is_composite(base_t) || !base_t->name_off)
|
||||
continue;
|
||||
if (base_name_cnt[base_t->name_off] < 255)
|
||||
base_name_cnt[base_t->name_off]++;
|
||||
}
|
||||
|
||||
/* Now search base BTF for matching distilled base BTF types. */
|
||||
for (id = 1; id < r->nr_base_types; id++) {
|
||||
struct btf_name_info *dist_info, base_info = {};
|
||||
int dist_kind, base_kind;
|
||||
|
||||
base_t = btf_type_by_id(r->base_btf, id);
|
||||
/* distilled base consists of named types only. */
|
||||
if (!base_t->name_off)
|
||||
continue;
|
||||
base_kind = btf_kind(base_t);
|
||||
base_info.id = id;
|
||||
base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off);
|
||||
switch (base_kind) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_ENUM64:
|
||||
/* These types should match both name and size */
|
||||
base_info.needs_size = true;
|
||||
base_info.size = base_t->size;
|
||||
break;
|
||||
case BTF_KIND_FWD:
|
||||
/* No size considerations for fwds. */
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
/* Size only needs to be used for struct/union if there
|
||||
* are multiple types in base BTF with the same name.
|
||||
* If there are multiple _distilled_ types with the same
|
||||
* name (a very unlikely scenario), that doesn't matter
|
||||
* unless corresponding _base_ types to match them are
|
||||
* missing.
|
||||
*/
|
||||
base_info.needs_size = base_name_cnt[base_t->name_off] > 1;
|
||||
base_info.size = base_t->size;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
/* iterate over all matching distilled base types */
|
||||
for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types);
|
||||
dist_info != NULL && dist_info < info_end &&
|
||||
cmp_btf_name_size(&base_info, dist_info) == 0;
|
||||
dist_info++) {
|
||||
if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) {
|
||||
pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n",
|
||||
id, dist_info->id);
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id);
|
||||
dist_kind = btf_kind(dist_t);
|
||||
|
||||
/* Validate that the found distilled type is compatible.
|
||||
* Do not error out on mismatch as another match may
|
||||
* occur for an identically-named type.
|
||||
*/
|
||||
switch (dist_kind) {
|
||||
case BTF_KIND_FWD:
|
||||
switch (base_kind) {
|
||||
case BTF_KIND_FWD:
|
||||
if (btf_kflag(dist_t) != btf_kflag(base_t))
|
||||
continue;
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
if (btf_kflag(base_t))
|
||||
continue;
|
||||
break;
|
||||
case BTF_KIND_UNION:
|
||||
if (!btf_kflag(base_t))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case BTF_KIND_INT:
|
||||
if (dist_kind != base_kind ||
|
||||
btf_int_encoding(base_t) != btf_int_encoding(dist_t))
|
||||
continue;
|
||||
break;
|
||||
case BTF_KIND_FLOAT:
|
||||
if (dist_kind != base_kind)
|
||||
continue;
|
||||
break;
|
||||
case BTF_KIND_ENUM:
|
||||
/* ENUM and ENUM64 are encoded as sized ENUM in
|
||||
* distilled base BTF.
|
||||
*/
|
||||
if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64)
|
||||
continue;
|
||||
break;
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
/* size verification is required for embedded
|
||||
* struct/unions.
|
||||
*/
|
||||
if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED &&
|
||||
base_t->size != dist_t->size)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (r->id_map[dist_info->id] &&
|
||||
r->id_map[dist_info->id] != BTF_IS_EMBEDDED) {
|
||||
/* we already have a match; this tells us that
|
||||
* multiple base types of the same name
|
||||
* have the same size, since for cases where
|
||||
* multiple types have the same name we match
|
||||
* on name and size. In this case, we have
|
||||
* no way of determining which to relocate
|
||||
* to in base BTF, so error out.
|
||||
*/
|
||||
pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n",
|
||||
base_info.name, dist_info->id,
|
||||
base_t->size, id, r->id_map[dist_info->id]);
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
/* map id and name */
|
||||
r->id_map[dist_info->id] = id;
|
||||
r->str_map[dist_t->name_off] = base_t->name_off;
|
||||
}
|
||||
}
|
||||
/* ensure all distilled BTF ids now have a mapping... */
|
||||
for (id = 1; id < r->nr_dist_base_types; id++) {
|
||||
const char *name;
|
||||
|
||||
if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED)
|
||||
continue;
|
||||
dist_t = btf_type_by_id(r->dist_base_btf, id);
|
||||
name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
|
||||
pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n",
|
||||
name, id);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
free(base_name_cnt);
|
||||
free(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* distilled base should only have named int/float/enum/fwd/struct/union types. */
|
||||
static int btf_relocate_validate_distilled_base(struct btf_relocate *r)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i < r->nr_dist_base_types; i++) {
|
||||
struct btf_type *t = btf_type_by_id(r->dist_base_btf, i);
|
||||
int kind = btf_kind(t);
|
||||
|
||||
switch (kind) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
case BTF_KIND_FWD:
|
||||
if (t->name_off)
|
||||
break;
|
||||
pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n",
|
||||
i, kind);
|
||||
return -EINVAL;
|
||||
default:
|
||||
pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n",
|
||||
i, kind);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i)
|
||||
{
|
||||
struct btf_type *t = btf_type_by_id(r->btf, i);
|
||||
struct btf_field_iter it;
|
||||
__u32 *str_off;
|
||||
int off, err;
|
||||
|
||||
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while ((str_off = btf_field_iter_next(&it))) {
|
||||
if (!*str_off)
|
||||
continue;
|
||||
if (*str_off >= r->dist_str_len) {
|
||||
*str_off += r->base_str_len - r->dist_str_len;
|
||||
} else {
|
||||
off = r->str_map[*str_off];
|
||||
if (!off) {
|
||||
pr_warn("string '%s' [offset %u] is not mapped to base BTF\n",
|
||||
btf__str_by_offset(r->btf, off), *str_off);
|
||||
return -ENOENT;
|
||||
}
|
||||
*str_off = off;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If successful, output of relocation is updated BTF with base BTF pointing
|
||||
* at base_btf, and type ids, strings adjusted accordingly.
|
||||
*/
|
||||
int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map)
|
||||
{
|
||||
unsigned int nr_types = btf__type_cnt(btf);
|
||||
const struct btf_header *dist_base_hdr;
|
||||
const struct btf_header *base_hdr;
|
||||
struct btf_relocate r = {};
|
||||
int err = 0;
|
||||
__u32 id, i;
|
||||
|
||||
r.dist_base_btf = btf__base_btf(btf);
|
||||
if (!base_btf || r.dist_base_btf == base_btf)
|
||||
return -EINVAL;
|
||||
|
||||
r.nr_dist_base_types = btf__type_cnt(r.dist_base_btf);
|
||||
r.nr_base_types = btf__type_cnt(base_btf);
|
||||
r.nr_split_types = nr_types - r.nr_dist_base_types;
|
||||
r.btf = btf;
|
||||
r.base_btf = base_btf;
|
||||
|
||||
r.id_map = calloc(nr_types, sizeof(*r.id_map));
|
||||
r.str_map = calloc(btf_header(r.dist_base_btf)->str_len, sizeof(*r.str_map));
|
||||
dist_base_hdr = btf_header(r.dist_base_btf);
|
||||
base_hdr = btf_header(r.base_btf);
|
||||
r.dist_str_len = dist_base_hdr->str_len;
|
||||
r.base_str_len = base_hdr->str_len;
|
||||
if (!r.id_map || !r.str_map) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = btf_relocate_validate_distilled_base(&r);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* Split BTF ids need to be adjusted as base and distilled base
|
||||
* have different numbers of types, changing the start id of split
|
||||
* BTF.
|
||||
*/
|
||||
for (id = r.nr_dist_base_types; id < nr_types; id++)
|
||||
r.id_map[id] = id + r.nr_base_types - r.nr_dist_base_types;
|
||||
|
||||
/* Build a map from distilled base ids to actual base BTF ids; it is used
|
||||
* to update split BTF id references. Also build a str_map mapping from
|
||||
* distilled base BTF names to base BTF names.
|
||||
*/
|
||||
err = btf_relocate_map_distilled_base(&r);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* Next, rewrite type ids in split BTF, replacing split ids with updated
|
||||
* ids based on number of types in base BTF, and base ids with
|
||||
* relocated ids from base_btf.
|
||||
*/
|
||||
for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) {
|
||||
err = btf_relocate_rewrite_type_id(&r, id);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
/* String offsets now need to be updated using the str_map. */
|
||||
for (i = 0; i < r.nr_split_types; i++) {
|
||||
err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
/* Finally reset base BTF to be base_btf */
|
||||
btf_set_base_btf(btf, base_btf);
|
||||
|
||||
if (id_map) {
|
||||
*id_map = r.id_map;
|
||||
r.id_map = NULL;
|
||||
}
|
||||
err_out:
|
||||
free(r.id_map);
|
||||
free(r.str_map);
|
||||
return err;
|
||||
}
|
||||
559
src/elf.c
559
src/elf.c
@@ -1,559 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "libbpf_internal.h"
|
||||
#include "str_error.h"
|
||||
|
||||
/* A SHT_GNU_versym section holds 16-bit words. This bit is set if
|
||||
* the symbol is hidden and can only be seen when referenced using an
|
||||
* explicit version number. This is a GNU extension.
|
||||
*/
|
||||
#define VERSYM_HIDDEN 0x8000
|
||||
|
||||
/* This is the mask for the rest of the data in a word read from a
|
||||
* SHT_GNU_versym section.
|
||||
*/
|
||||
#define VERSYM_VERSION 0x7fff
|
||||
|
||||
int elf_open(const char *binary_path, struct elf_fd *elf_fd)
|
||||
{
|
||||
int fd, ret;
|
||||
Elf *elf;
|
||||
|
||||
elf_fd->elf = NULL;
|
||||
elf_fd->fd = -1;
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||
pr_warn("elf: failed to init libelf for %s\n", binary_path);
|
||||
return -LIBBPF_ERRNO__LIBELF;
|
||||
}
|
||||
fd = open(binary_path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("elf: failed to open %s: %s\n", binary_path, errstr(ret));
|
||||
return ret;
|
||||
}
|
||||
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!elf) {
|
||||
pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
close(fd);
|
||||
return -LIBBPF_ERRNO__FORMAT;
|
||||
}
|
||||
elf_fd->fd = fd;
|
||||
elf_fd->elf = elf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void elf_close(struct elf_fd *elf_fd)
|
||||
{
|
||||
if (!elf_fd)
|
||||
return;
|
||||
elf_end(elf_fd->elf);
|
||||
close(elf_fd->fd);
|
||||
}
|
||||
|
||||
/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
|
||||
static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
|
||||
{
|
||||
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||
GElf_Shdr sh;
|
||||
|
||||
if (!gelf_getshdr(scn, &sh))
|
||||
continue;
|
||||
if (sh.sh_type == sh_type)
|
||||
return scn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_sym {
|
||||
const char *name;
|
||||
GElf_Sym sym;
|
||||
GElf_Shdr sh;
|
||||
int ver;
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
struct elf_sym_iter {
|
||||
Elf *elf;
|
||||
Elf_Data *syms;
|
||||
Elf_Data *versyms;
|
||||
Elf_Data *verdefs;
|
||||
size_t nr_syms;
|
||||
size_t strtabidx;
|
||||
size_t verdef_strtabidx;
|
||||
size_t next_sym_idx;
|
||||
struct elf_sym sym;
|
||||
int st_type;
|
||||
};
|
||||
|
||||
static int elf_sym_iter_new(struct elf_sym_iter *iter,
|
||||
Elf *elf, const char *binary_path,
|
||||
int sh_type, int st_type)
|
||||
{
|
||||
Elf_Scn *scn = NULL;
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr sh;
|
||||
|
||||
memset(iter, 0, sizeof(*iter));
|
||||
|
||||
if (!gelf_getehdr(elf, &ehdr)) {
|
||||
pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, sh_type, NULL);
|
||||
if (!scn) {
|
||||
pr_debug("elf: failed to find symbol table ELF sections in '%s'\n",
|
||||
binary_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!gelf_getshdr(scn, &sh))
|
||||
return -EINVAL;
|
||||
|
||||
iter->strtabidx = sh.sh_link;
|
||||
iter->syms = elf_getdata(scn, 0);
|
||||
if (!iter->syms) {
|
||||
pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n",
|
||||
binary_path, elf_errmsg(-1));
|
||||
return -EINVAL;
|
||||
}
|
||||
iter->nr_syms = iter->syms->d_size / sh.sh_entsize;
|
||||
iter->elf = elf;
|
||||
iter->st_type = st_type;
|
||||
|
||||
/* Version symbol table is meaningful to dynsym only */
|
||||
if (sh_type != SHT_DYNSYM)
|
||||
return 0;
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, SHT_GNU_versym, NULL);
|
||||
if (!scn)
|
||||
return 0;
|
||||
iter->versyms = elf_getdata(scn, 0);
|
||||
|
||||
scn = elf_find_next_scn_by_type(elf, SHT_GNU_verdef, NULL);
|
||||
if (!scn)
|
||||
return 0;
|
||||
|
||||
iter->verdefs = elf_getdata(scn, 0);
|
||||
if (!iter->verdefs || !gelf_getshdr(scn, &sh)) {
|
||||
pr_warn("elf: failed to get verdef ELF section in '%s'\n", binary_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
iter->verdef_strtabidx = sh.sh_link;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct elf_sym *elf_sym_iter_next(struct elf_sym_iter *iter)
|
||||
{
|
||||
struct elf_sym *ret = &iter->sym;
|
||||
GElf_Sym *sym = &ret->sym;
|
||||
const char *name = NULL;
|
||||
GElf_Versym versym;
|
||||
Elf_Scn *sym_scn;
|
||||
size_t idx;
|
||||
|
||||
for (idx = iter->next_sym_idx; idx < iter->nr_syms; idx++) {
|
||||
if (!gelf_getsym(iter->syms, idx, sym))
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym->st_info) != iter->st_type)
|
||||
continue;
|
||||
name = elf_strptr(iter->elf, iter->strtabidx, sym->st_name);
|
||||
if (!name)
|
||||
continue;
|
||||
sym_scn = elf_getscn(iter->elf, sym->st_shndx);
|
||||
if (!sym_scn)
|
||||
continue;
|
||||
if (!gelf_getshdr(sym_scn, &ret->sh))
|
||||
continue;
|
||||
|
||||
iter->next_sym_idx = idx + 1;
|
||||
ret->name = name;
|
||||
ret->ver = 0;
|
||||
ret->hidden = false;
|
||||
|
||||
if (iter->versyms) {
|
||||
if (!gelf_getversym(iter->versyms, idx, &versym))
|
||||
continue;
|
||||
ret->ver = versym & VERSYM_VERSION;
|
||||
ret->hidden = versym & VERSYM_HIDDEN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *elf_get_vername(struct elf_sym_iter *iter, int ver)
|
||||
{
|
||||
GElf_Verdaux verdaux;
|
||||
GElf_Verdef verdef;
|
||||
int offset;
|
||||
|
||||
if (!iter->verdefs)
|
||||
return NULL;
|
||||
|
||||
offset = 0;
|
||||
while (gelf_getverdef(iter->verdefs, offset, &verdef)) {
|
||||
if (verdef.vd_ndx != ver) {
|
||||
if (!verdef.vd_next)
|
||||
break;
|
||||
|
||||
offset += verdef.vd_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!gelf_getverdaux(iter->verdefs, offset + verdef.vd_aux, &verdaux))
|
||||
break;
|
||||
|
||||
return elf_strptr(iter->elf, iter->verdef_strtabidx, verdaux.vda_name);
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool symbol_match(struct elf_sym_iter *iter, int sh_type, struct elf_sym *sym,
|
||||
const char *name, size_t name_len, const char *lib_ver)
|
||||
{
|
||||
const char *ver_name;
|
||||
|
||||
/* Symbols are in forms of func, func@LIB_VER or func@@LIB_VER
|
||||
* make sure the func part matches the user specified name
|
||||
*/
|
||||
if (strncmp(sym->name, name, name_len) != 0)
|
||||
return false;
|
||||
|
||||
/* ...but we don't want a search for "foo" to match 'foo2" also, so any
|
||||
* additional characters in sname should be of the form "@@LIB".
|
||||
*/
|
||||
if (sym->name[name_len] != '\0' && sym->name[name_len] != '@')
|
||||
return false;
|
||||
|
||||
/* If user does not specify symbol version, then we got a match */
|
||||
if (!lib_ver)
|
||||
return true;
|
||||
|
||||
/* If user specifies symbol version, for dynamic symbols,
|
||||
* get version name from ELF verdef section for comparison.
|
||||
*/
|
||||
if (sh_type == SHT_DYNSYM) {
|
||||
ver_name = elf_get_vername(iter, sym->ver);
|
||||
if (!ver_name)
|
||||
return false;
|
||||
return strcmp(ver_name, lib_ver) == 0;
|
||||
}
|
||||
|
||||
/* For normal symbols, it is already in form of func@LIB_VER */
|
||||
return strcmp(sym->name, name) == 0;
|
||||
}
|
||||
|
||||
/* Transform symbol's virtual address (absolute for binaries and relative
|
||||
* for shared libs) into file offset, which is what kernel is expecting
|
||||
* for uprobe/uretprobe attachment.
|
||||
* See Documentation/trace/uprobetracer.rst for more details. This is done
|
||||
* by looking up symbol's containing section's header and using iter's virtual
|
||||
* address (sh_addr) and corresponding file offset (sh_offset) to transform
|
||||
* sym.st_value (virtual address) into desired final file offset.
|
||||
*/
|
||||
static unsigned long elf_sym_offset(struct elf_sym *sym)
|
||||
{
|
||||
return sym->sym.st_value - sym->sh.sh_addr + sym->sh.sh_offset;
|
||||
}
|
||||
|
||||
/* Find offset of function name in the provided ELF object. "binary_path" is
|
||||
* the path to the ELF binary represented by "elf", and only used for error
|
||||
* reporting matters. "name" matches symbol name or name@@LIB for library
|
||||
* functions.
|
||||
*/
|
||||
long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name)
|
||||
{
|
||||
int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
|
||||
const char *at_symbol, *lib_ver;
|
||||
bool is_shared_lib;
|
||||
long ret = -ENOENT;
|
||||
size_t name_len;
|
||||
GElf_Ehdr ehdr;
|
||||
|
||||
if (!gelf_getehdr(elf, &ehdr)) {
|
||||
pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
|
||||
ret = -LIBBPF_ERRNO__FORMAT;
|
||||
goto out;
|
||||
}
|
||||
/* for shared lib case, we do not need to calculate relative offset */
|
||||
is_shared_lib = ehdr.e_type == ET_DYN;
|
||||
|
||||
/* Does name specify "@@LIB_VER" or "@LIB_VER" ? */
|
||||
at_symbol = strchr(name, '@');
|
||||
if (at_symbol) {
|
||||
name_len = at_symbol - name;
|
||||
/* skip second @ if it's @@LIB_VER case */
|
||||
if (at_symbol[1] == '@')
|
||||
at_symbol++;
|
||||
lib_ver = at_symbol + 1;
|
||||
} else {
|
||||
name_len = strlen(name);
|
||||
lib_ver = NULL;
|
||||
}
|
||||
|
||||
/* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if
|
||||
* a binary is stripped, it may only have SHT_DYNSYM, and a fully-statically
|
||||
* linked binary may not have SHT_DYMSYM, so absence of a section should not be
|
||||
* reported as a warning/error.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
int last_bind = -1;
|
||||
int cur_bind;
|
||||
|
||||
ret = elf_sym_iter_new(&iter, elf, binary_path, sh_types[i], STT_FUNC);
|
||||
if (ret == -ENOENT)
|
||||
continue;
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
if (!symbol_match(&iter, sh_types[i], sym, name, name_len, lib_ver))
|
||||
continue;
|
||||
|
||||
cur_bind = GELF_ST_BIND(sym->sym.st_info);
|
||||
|
||||
if (ret > 0) {
|
||||
/* handle multiple matches */
|
||||
if (elf_sym_offset(sym) == ret) {
|
||||
/* same offset, no problem */
|
||||
continue;
|
||||
} else if (last_bind != STB_WEAK && cur_bind != STB_WEAK) {
|
||||
/* Only accept one non-weak bind. */
|
||||
pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n",
|
||||
sym->name, name, binary_path);
|
||||
ret = -LIBBPF_ERRNO__FORMAT;
|
||||
goto out;
|
||||
} else if (cur_bind == STB_WEAK) {
|
||||
/* already have a non-weak bind, and
|
||||
* this is a weak bind, so ignore.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret = elf_sym_offset(sym);
|
||||
last_bind = cur_bind;
|
||||
}
|
||||
if (ret > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
|
||||
ret);
|
||||
} else {
|
||||
if (ret == 0) {
|
||||
pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path,
|
||||
is_shared_lib ? "should not be 0 in a shared library" :
|
||||
"try using shared library path instead");
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find offset of function name in ELF object specified by path. "name" matches
|
||||
* symbol name or name@@LIB for library functions.
|
||||
*/
|
||||
long elf_find_func_offset_from_file(const char *binary_path, const char *name)
|
||||
{
|
||||
struct elf_fd elf_fd;
|
||||
long ret = -ENOENT;
|
||||
|
||||
ret = elf_open(binary_path, &elf_fd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = elf_find_func_offset(elf_fd.elf, binary_path, name);
|
||||
elf_close(&elf_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct symbol {
|
||||
const char *name;
|
||||
int bind;
|
||||
int idx;
|
||||
};
|
||||
|
||||
static int symbol_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct symbol *sym_a = a;
|
||||
const struct symbol *sym_b = b;
|
||||
|
||||
return strcmp(sym_a->name, sym_b->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offsets in @poffsets for symbols specified in @syms array argument.
|
||||
* On success returns 0 and offsets are returned in allocated array with @cnt
|
||||
* size, that needs to be released by the caller.
|
||||
*/
|
||||
int elf_resolve_syms_offsets(const char *binary_path, int cnt,
|
||||
const char **syms, unsigned long **poffsets,
|
||||
int st_type)
|
||||
{
|
||||
int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB };
|
||||
int err = 0, i, cnt_done = 0;
|
||||
unsigned long *offsets;
|
||||
struct symbol *symbols;
|
||||
struct elf_fd elf_fd;
|
||||
|
||||
err = elf_open(binary_path, &elf_fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
offsets = calloc(cnt, sizeof(*offsets));
|
||||
symbols = calloc(cnt, sizeof(*symbols));
|
||||
|
||||
if (!offsets || !symbols) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
symbols[i].name = syms[i];
|
||||
symbols[i].idx = i;
|
||||
}
|
||||
|
||||
qsort(symbols, cnt, sizeof(*symbols), symbol_cmp);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
|
||||
err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], st_type);
|
||||
if (err == -ENOENT)
|
||||
continue;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
unsigned long sym_offset = elf_sym_offset(sym);
|
||||
int bind = GELF_ST_BIND(sym->sym.st_info);
|
||||
struct symbol *found, tmp = {
|
||||
.name = sym->name,
|
||||
};
|
||||
unsigned long *offset;
|
||||
|
||||
found = bsearch(&tmp, symbols, cnt, sizeof(*symbols), symbol_cmp);
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
offset = &offsets[found->idx];
|
||||
if (*offset > 0) {
|
||||
/* same offset, no problem */
|
||||
if (*offset == sym_offset)
|
||||
continue;
|
||||
/* handle multiple matches */
|
||||
if (found->bind != STB_WEAK && bind != STB_WEAK) {
|
||||
/* Only accept one non-weak bind. */
|
||||
pr_warn("elf: ambiguous match found '%s@%lu' in '%s' previous offset %lu\n",
|
||||
sym->name, sym_offset, binary_path, *offset);
|
||||
err = -ESRCH;
|
||||
goto out;
|
||||
} else if (bind == STB_WEAK) {
|
||||
/* already have a non-weak bind, and
|
||||
* this is a weak bind, so ignore.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
cnt_done++;
|
||||
}
|
||||
*offset = sym_offset;
|
||||
found->bind = bind;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt != cnt_done) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*poffsets = offsets;
|
||||
|
||||
out:
|
||||
free(symbols);
|
||||
if (err)
|
||||
free(offsets);
|
||||
elf_close(&elf_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return offsets in @poffsets for symbols specified by @pattern argument.
|
||||
* On success returns 0 and offsets are returned in allocated @poffsets
|
||||
* array with the @pctn size, that needs to be released by the caller.
|
||||
*/
|
||||
int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
|
||||
unsigned long **poffsets, size_t *pcnt)
|
||||
{
|
||||
int sh_types[2] = { SHT_SYMTAB, SHT_DYNSYM };
|
||||
unsigned long *offsets = NULL;
|
||||
size_t cap = 0, cnt = 0;
|
||||
struct elf_fd elf_fd;
|
||||
int err = 0, i;
|
||||
|
||||
err = elf_open(binary_path, &elf_fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sh_types); i++) {
|
||||
struct elf_sym_iter iter;
|
||||
struct elf_sym *sym;
|
||||
|
||||
err = elf_sym_iter_new(&iter, elf_fd.elf, binary_path, sh_types[i], STT_FUNC);
|
||||
if (err == -ENOENT)
|
||||
continue;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while ((sym = elf_sym_iter_next(&iter))) {
|
||||
if (!glob_match(sym->name, pattern))
|
||||
continue;
|
||||
|
||||
err = libbpf_ensure_mem((void **) &offsets, &cap, sizeof(*offsets),
|
||||
cnt + 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
offsets[cnt++] = elf_sym_offset(sym);
|
||||
}
|
||||
|
||||
/* If we found anything in the first symbol section,
|
||||
* do not search others to avoid duplicates.
|
||||
*/
|
||||
if (cnt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cnt) {
|
||||
*poffsets = offsets;
|
||||
*pcnt = cnt;
|
||||
} else {
|
||||
err = -ENOENT;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
free(offsets);
|
||||
elf_close(&elf_fd);
|
||||
return err;
|
||||
}
|
||||
610
src/features.c
610
src/features.c
@@ -1,610 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/filter.h>
|
||||
#include "bpf.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_common.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "str_error.h"
|
||||
|
||||
static inline __u64 ptr_to_u64(const void *ptr)
|
||||
{
|
||||
return (__u64)(unsigned long)ptr;
|
||||
}
|
||||
|
||||
int probe_fd(int fd)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
static int probe_kern_prog_name(int token_fd)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
union bpf_attr attr;
|
||||
int ret;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||
attr.license = ptr_to_u64("GPL");
|
||||
attr.insns = ptr_to_u64(insns);
|
||||
attr.insn_cnt = (__u32)ARRAY_SIZE(insns);
|
||||
attr.prog_token_fd = token_fd;
|
||||
if (token_fd)
|
||||
attr.prog_flags |= BPF_F_TOKEN_FD;
|
||||
libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name));
|
||||
|
||||
/* make sure loading with name works */
|
||||
ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_global_data(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||
.token_fd = token_fd,
|
||||
.map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, map, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts);
|
||||
if (map < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("Error in %s(): %s. Couldn't create simple array map.\n",
|
||||
__func__, errstr(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
insns[0].imm = map;
|
||||
|
||||
ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
|
||||
close(map);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_btf(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_func(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int\0x\0a";
|
||||
/* void x(int a) {} */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* FUNC_PROTO */ /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
|
||||
BTF_PARAM_ENC(7, 1),
|
||||
/* FUNC x */ /* [3] */
|
||||
BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_func_global(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int\0x\0a";
|
||||
/* static void x(int a) {} */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* FUNC_PROTO */ /* [2] */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0),
|
||||
BTF_PARAM_ENC(7, 1),
|
||||
/* FUNC x BTF_FUNC_GLOBAL */ /* [3] */
|
||||
BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_datasec(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0x\0.data";
|
||||
/* static int a; */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* DATASEC val */ /* [3] */
|
||||
BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_qmark_datasec(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0x\0?.data";
|
||||
/* static int a; */
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* DATASEC ?.data */ /* [3] */
|
||||
BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4),
|
||||
BTF_VAR_SECINFO_ENC(2, 0, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_float(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0float";
|
||||
__u32 types[] = {
|
||||
/* float */
|
||||
BTF_TYPE_FLOAT_ENC(1, 4),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_decl_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0tag";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* VAR x */ /* [2] */
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1),
|
||||
BTF_VAR_STATIC,
|
||||
/* attr */
|
||||
BTF_TYPE_DECL_TAG_ENC(1, 2, -1),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_btf_type_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0tag";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||
/* attr */
|
||||
BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */
|
||||
/* ptr */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_array_mmap(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts,
|
||||
.map_flags = BPF_F_MMAPABLE | (token_fd ? BPF_F_TOKEN_FD : 0),
|
||||
.token_fd = token_fd,
|
||||
);
|
||||
int fd;
|
||||
|
||||
fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_kern_exp_attach_type(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
/* use any valid combination of program type and (optional)
|
||||
* non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS)
|
||||
* to see if kernel supports expected_attach_type field for
|
||||
* BPF_PROG_LOAD command
|
||||
*/
|
||||
fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_kern_probe_read_kernel(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */
|
||||
BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */
|
||||
BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(fd);
|
||||
}
|
||||
|
||||
static int probe_prog_bind_map(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, map_opts,
|
||||
.token_fd = token_fd,
|
||||
.map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, map, prog, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts);
|
||||
if (map < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("Error in %s(): %s. Couldn't create simple array map.\n",
|
||||
__func__, errstr(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts);
|
||||
if (prog < 0) {
|
||||
close(map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = bpf_prog_bind_map(prog, map, NULL);
|
||||
|
||||
close(map);
|
||||
close(prog);
|
||||
|
||||
return ret >= 0;
|
||||
}
|
||||
|
||||
static int probe_module_btf(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0int";
|
||||
__u32 types[] = {
|
||||
/* int */
|
||||
BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
|
||||
};
|
||||
struct bpf_btf_info info;
|
||||
__u32 len = sizeof(info);
|
||||
char name[16];
|
||||
int fd, err;
|
||||
|
||||
fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
|
||||
if (fd < 0)
|
||||
return 0; /* BTF not supported at all */
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.name = ptr_to_u64(name);
|
||||
info.name_len = sizeof(name);
|
||||
|
||||
/* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer;
|
||||
* kernel's module BTF support coincides with support for
|
||||
* name/name_len fields in struct bpf_btf_info.
|
||||
*/
|
||||
err = bpf_btf_get_info_by_fd(fd, &info, &len);
|
||||
close(fd);
|
||||
return !err;
|
||||
}
|
||||
|
||||
static int probe_perf_link(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int prog_fd, link_fd, err;
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL",
|
||||
insns, ARRAY_SIZE(insns), &opts);
|
||||
if (prog_fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* use invalid perf_event FD to get EBADF, if link is supported;
|
||||
* otherwise EINVAL should be returned
|
||||
*/
|
||||
link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL);
|
||||
err = -errno; /* close() can clobber errno */
|
||||
|
||||
if (link_fd >= 0)
|
||||
close(link_fd);
|
||||
close(prog_fd);
|
||||
|
||||
return link_fd < 0 && err == -EBADF;
|
||||
}
|
||||
|
||||
static int probe_uprobe_multi_link(int token_fd)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, load_opts,
|
||||
.expected_attach_type = BPF_TRACE_UPROBE_MULTI,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
LIBBPF_OPTS(bpf_link_create_opts, link_opts);
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int prog_fd, link_fd, err;
|
||||
unsigned long offset = 0;
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL",
|
||||
insns, ARRAY_SIZE(insns), &load_opts);
|
||||
if (prog_fd < 0)
|
||||
return -errno;
|
||||
|
||||
/* Creating uprobe in '/' binary should fail with -EBADF. */
|
||||
link_opts.uprobe_multi.path = "/";
|
||||
link_opts.uprobe_multi.offsets = &offset;
|
||||
link_opts.uprobe_multi.cnt = 1;
|
||||
|
||||
link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts);
|
||||
err = -errno; /* close() can clobber errno */
|
||||
|
||||
if (link_fd >= 0 || err != -EBADF) {
|
||||
if (link_fd >= 0)
|
||||
close(link_fd);
|
||||
close(prog_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initial multi-uprobe support in kernel didn't handle PID filtering
|
||||
* correctly (it was doing thread filtering, not process filtering).
|
||||
* So now we'll detect if PID filtering logic was fixed, and, if not,
|
||||
* we'll pretend multi-uprobes are not supported, if not.
|
||||
* Multi-uprobes are used in USDT attachment logic, and we need to be
|
||||
* conservative here, because multi-uprobe selection happens early at
|
||||
* load time, while the use of PID filtering is known late at
|
||||
* attachment time, at which point it's too late to undo multi-uprobe
|
||||
* selection.
|
||||
*
|
||||
* Creating uprobe with pid == -1 for (invalid) '/' binary will fail
|
||||
* early with -EINVAL on kernels with fixed PID filtering logic;
|
||||
* otherwise -ESRCH would be returned if passed correct binary path
|
||||
* (but we'll just get -BADF, of course).
|
||||
*/
|
||||
link_opts.uprobe_multi.pid = -1; /* invalid PID */
|
||||
link_opts.uprobe_multi.path = "/"; /* invalid path */
|
||||
link_opts.uprobe_multi.offsets = &offset;
|
||||
link_opts.uprobe_multi.cnt = 1;
|
||||
|
||||
link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts);
|
||||
err = -errno; /* close() can clobber errno */
|
||||
|
||||
if (link_fd >= 0)
|
||||
close(link_fd);
|
||||
close(prog_fd);
|
||||
|
||||
return link_fd < 0 && err == -EINVAL;
|
||||
}
|
||||
|
||||
static int probe_kern_bpf_cookie(int token_fd)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int ret, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts);
|
||||
return probe_fd(ret);
|
||||
}
|
||||
|
||||
static int probe_kern_btf_enum64(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0enum64";
|
||||
__u32 types[] = {
|
||||
BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
|
||||
};
|
||||
|
||||
return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), token_fd));
|
||||
}
|
||||
|
||||
static int probe_kern_arg_ctx_tag(int token_fd)
|
||||
{
|
||||
static const char strs[] = "\0a\0b\0arg:ctx\0";
|
||||
const __u32 types[] = {
|
||||
/* [1] INT */
|
||||
BTF_TYPE_INT_ENC(1 /* "a" */, BTF_INT_SIGNED, 0, 32, 4),
|
||||
/* [2] PTR -> VOID */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
|
||||
/* [3] FUNC_PROTO `int(void *a)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(1 /* "a" */, 2),
|
||||
/* [4] FUNC 'a' -> FUNC_PROTO (main prog) */
|
||||
BTF_TYPE_ENC(1 /* "a" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 3),
|
||||
/* [5] FUNC_PROTO `int(void *b __arg_ctx)` */
|
||||
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 1),
|
||||
BTF_PARAM_ENC(3 /* "b" */, 2),
|
||||
/* [6] FUNC 'b' -> FUNC_PROTO (subprog) */
|
||||
BTF_TYPE_ENC(3 /* "b" */, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 5),
|
||||
/* [7] DECL_TAG 'arg:ctx' -> func 'b' arg 'b' */
|
||||
BTF_TYPE_DECL_TAG_ENC(5 /* "arg:ctx" */, 6, 0),
|
||||
};
|
||||
const struct bpf_insn insns[] = {
|
||||
/* main prog */
|
||||
BPF_CALL_REL(+1),
|
||||
BPF_EXIT_INSN(),
|
||||
/* global subprog */
|
||||
BPF_EMIT_CALL(BPF_FUNC_get_func_ip), /* needs PTR_TO_CTX */
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
const struct bpf_func_info_min func_infos[] = {
|
||||
{ 0, 4 }, /* main prog -> FUNC 'a' */
|
||||
{ 2, 6 }, /* subprog -> FUNC 'b' */
|
||||
};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int prog_fd, btf_fd, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
btf_fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd);
|
||||
if (btf_fd < 0)
|
||||
return 0;
|
||||
|
||||
opts.prog_btf_fd = btf_fd;
|
||||
opts.func_info = &func_infos;
|
||||
opts.func_info_cnt = ARRAY_SIZE(func_infos);
|
||||
opts.func_info_rec_size = sizeof(func_infos[0]);
|
||||
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, "det_arg_ctx",
|
||||
"GPL", insns, insn_cnt, &opts);
|
||||
close(btf_fd);
|
||||
|
||||
return probe_fd(prog_fd);
|
||||
}
|
||||
|
||||
typedef int (*feature_probe_fn)(int /* token_fd */);
|
||||
|
||||
static struct kern_feature_cache feature_cache;
|
||||
|
||||
static struct kern_feature_desc {
|
||||
const char *desc;
|
||||
feature_probe_fn probe;
|
||||
} feature_probes[__FEAT_CNT] = {
|
||||
[FEAT_PROG_NAME] = {
|
||||
"BPF program name", probe_kern_prog_name,
|
||||
},
|
||||
[FEAT_GLOBAL_DATA] = {
|
||||
"global variables", probe_kern_global_data,
|
||||
},
|
||||
[FEAT_BTF] = {
|
||||
"minimal BTF", probe_kern_btf,
|
||||
},
|
||||
[FEAT_BTF_FUNC] = {
|
||||
"BTF functions", probe_kern_btf_func,
|
||||
},
|
||||
[FEAT_BTF_GLOBAL_FUNC] = {
|
||||
"BTF global function", probe_kern_btf_func_global,
|
||||
},
|
||||
[FEAT_BTF_DATASEC] = {
|
||||
"BTF data section and variable", probe_kern_btf_datasec,
|
||||
},
|
||||
[FEAT_ARRAY_MMAP] = {
|
||||
"ARRAY map mmap()", probe_kern_array_mmap,
|
||||
},
|
||||
[FEAT_EXP_ATTACH_TYPE] = {
|
||||
"BPF_PROG_LOAD expected_attach_type attribute",
|
||||
probe_kern_exp_attach_type,
|
||||
},
|
||||
[FEAT_PROBE_READ_KERN] = {
|
||||
"bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel,
|
||||
},
|
||||
[FEAT_PROG_BIND_MAP] = {
|
||||
"BPF_PROG_BIND_MAP support", probe_prog_bind_map,
|
||||
},
|
||||
[FEAT_MODULE_BTF] = {
|
||||
"module BTF support", probe_module_btf,
|
||||
},
|
||||
[FEAT_BTF_FLOAT] = {
|
||||
"BTF_KIND_FLOAT support", probe_kern_btf_float,
|
||||
},
|
||||
[FEAT_PERF_LINK] = {
|
||||
"BPF perf link support", probe_perf_link,
|
||||
},
|
||||
[FEAT_BTF_DECL_TAG] = {
|
||||
"BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag,
|
||||
},
|
||||
[FEAT_BTF_TYPE_TAG] = {
|
||||
"BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag,
|
||||
},
|
||||
[FEAT_MEMCG_ACCOUNT] = {
|
||||
"memcg-based memory accounting", probe_memcg_account,
|
||||
},
|
||||
[FEAT_BPF_COOKIE] = {
|
||||
"BPF cookie support", probe_kern_bpf_cookie,
|
||||
},
|
||||
[FEAT_BTF_ENUM64] = {
|
||||
"BTF_KIND_ENUM64 support", probe_kern_btf_enum64,
|
||||
},
|
||||
[FEAT_SYSCALL_WRAPPER] = {
|
||||
"Kernel using syscall wrapper", probe_kern_syscall_wrapper,
|
||||
},
|
||||
[FEAT_UPROBE_MULTI_LINK] = {
|
||||
"BPF multi-uprobe link support", probe_uprobe_multi_link,
|
||||
},
|
||||
[FEAT_ARG_CTX_TAG] = {
|
||||
"kernel-side __arg_ctx tag", probe_kern_arg_ctx_tag,
|
||||
},
|
||||
[FEAT_BTF_QMARK_DATASEC] = {
|
||||
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
|
||||
},
|
||||
};
|
||||
|
||||
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
|
||||
{
|
||||
struct kern_feature_desc *feat = &feature_probes[feat_id];
|
||||
int ret;
|
||||
|
||||
/* assume global feature cache, unless custom one is provided */
|
||||
if (!cache)
|
||||
cache = &feature_cache;
|
||||
|
||||
if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) {
|
||||
ret = feat->probe(cache->token_fd);
|
||||
if (ret > 0) {
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED);
|
||||
} else if (ret == 0) {
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
|
||||
} else {
|
||||
pr_warn("Detection of kernel %s support failed: %s\n",
|
||||
feat->desc, errstr(ret));
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
|
||||
}
|
||||
}
|
||||
|
||||
return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED;
|
||||
}
|
||||
248
src/gen_loader.c
248
src/gen_loader.c
@@ -14,7 +14,6 @@
|
||||
#include "bpf_gen_internal.h"
|
||||
#include "skel_internal.h"
|
||||
#include <asm/byteorder.h>
|
||||
#include "str_error.h"
|
||||
|
||||
#define MAX_USED_MAPS 64
|
||||
#define MAX_USED_PROGS 32
|
||||
@@ -394,7 +393,7 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
|
||||
blob_fd_array_off(gen, i));
|
||||
emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0));
|
||||
emit(gen, BPF_EXIT_INSN());
|
||||
pr_debug("gen: finish %s\n", errstr(gen->error));
|
||||
pr_debug("gen: finish %d\n", gen->error);
|
||||
if (!gen->error) {
|
||||
struct gen_loader_opts *opts = gen->opts;
|
||||
|
||||
@@ -402,15 +401,6 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
|
||||
opts->insns_sz = gen->insn_cur - gen->insn_start;
|
||||
opts->data = gen->data_start;
|
||||
opts->data_sz = gen->data_cur - gen->data_start;
|
||||
|
||||
/* use target endianness for embedded loader */
|
||||
if (gen->swapped_endian) {
|
||||
struct bpf_insn *insn = (struct bpf_insn *)opts->insns;
|
||||
int insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
|
||||
|
||||
for (i = 0; i < insn_cnt; i++)
|
||||
bpf_insn_bswap(insn++);
|
||||
}
|
||||
}
|
||||
return gen->error;
|
||||
}
|
||||
@@ -424,28 +414,6 @@ void bpf_gen__free(struct bpf_gen *gen)
|
||||
free(gen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fields of bpf_attr are set to values in native byte-order before being
|
||||
* written to the target-bound data blob, and may need endian conversion.
|
||||
* This macro allows providing the correct value in situ more simply than
|
||||
* writing a separate converter for *all fields* of *all records* included
|
||||
* in union bpf_attr. Note that sizeof(rval) should match the assignment
|
||||
* target to avoid runtime problems.
|
||||
*/
|
||||
#define tgt_endian(rval) ({ \
|
||||
typeof(rval) _val = (rval); \
|
||||
if (gen->swapped_endian) { \
|
||||
switch (sizeof(_val)) { \
|
||||
case 1: break; \
|
||||
case 2: _val = bswap_16(_val); break; \
|
||||
case 4: _val = bswap_32(_val); break; \
|
||||
case 8: _val = bswap_64(_val); break; \
|
||||
default: pr_warn("unsupported bswap size!\n"); \
|
||||
} \
|
||||
} \
|
||||
_val; \
|
||||
})
|
||||
|
||||
void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
|
||||
__u32 btf_raw_size)
|
||||
{
|
||||
@@ -454,12 +422,11 @@ void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
pr_debug("gen: load_btf: size %d\n", btf_raw_size);
|
||||
btf_data = add_data(gen, btf_raw_data, btf_raw_size);
|
||||
|
||||
attr.btf_size = tgt_endian(btf_raw_size);
|
||||
attr.btf_size = btf_raw_size;
|
||||
btf_load_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: load_btf: off %d size %d, attr: off %d size %d\n",
|
||||
btf_data, btf_raw_size, btf_load_attr, attr_size);
|
||||
|
||||
/* populate union bpf_attr with user provided log details */
|
||||
move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_level), 4,
|
||||
@@ -490,29 +457,28 @@ void bpf_gen__map_create(struct bpf_gen *gen,
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
attr.map_type = tgt_endian(map_type);
|
||||
attr.key_size = tgt_endian(key_size);
|
||||
attr.value_size = tgt_endian(value_size);
|
||||
attr.map_flags = tgt_endian(map_attr->map_flags);
|
||||
attr.map_extra = tgt_endian(map_attr->map_extra);
|
||||
attr.map_type = map_type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.map_flags = map_attr->map_flags;
|
||||
attr.map_extra = map_attr->map_extra;
|
||||
if (map_name)
|
||||
libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name));
|
||||
attr.numa_node = tgt_endian(map_attr->numa_node);
|
||||
attr.map_ifindex = tgt_endian(map_attr->map_ifindex);
|
||||
attr.max_entries = tgt_endian(max_entries);
|
||||
attr.btf_key_type_id = tgt_endian(map_attr->btf_key_type_id);
|
||||
attr.btf_value_type_id = tgt_endian(map_attr->btf_value_type_id);
|
||||
attr.numa_node = map_attr->numa_node;
|
||||
attr.map_ifindex = map_attr->map_ifindex;
|
||||
attr.max_entries = max_entries;
|
||||
attr.btf_key_type_id = map_attr->btf_key_type_id;
|
||||
attr.btf_value_type_id = map_attr->btf_value_type_id;
|
||||
|
||||
pr_debug("gen: map_create: %s idx %d type %d value_type_id %d\n",
|
||||
attr.map_name, map_idx, map_type, attr.btf_value_type_id);
|
||||
|
||||
map_create_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: map_create: %s idx %d type %d value_type_id %d, attr: off %d size %d\n",
|
||||
map_name, map_idx, map_type, map_attr->btf_value_type_id,
|
||||
map_create_attr, attr_size);
|
||||
|
||||
if (map_attr->btf_value_type_id)
|
||||
if (attr.btf_value_type_id)
|
||||
/* populate union bpf_attr with btf_fd saved in the stack earlier */
|
||||
move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
|
||||
stack_off(btf_fd));
|
||||
switch (map_type) {
|
||||
switch (attr.map_type) {
|
||||
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||
move_stack2blob(gen, attr_field(map_create_attr, inner_map_fd), 4,
|
||||
@@ -532,8 +498,8 @@ void bpf_gen__map_create(struct bpf_gen *gen,
|
||||
/* emit MAP_CREATE command */
|
||||
emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size);
|
||||
debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d",
|
||||
map_name, map_idx, map_type, value_size,
|
||||
map_attr->btf_value_type_id);
|
||||
attr.map_name, map_idx, map_type, value_size,
|
||||
attr.btf_value_type_id);
|
||||
emit_check_err(gen);
|
||||
/* remember map_fd in the stack, if successful */
|
||||
if (map_idx < 0) {
|
||||
@@ -594,7 +560,7 @@ static void emit_find_attach_target(struct bpf_gen *gen)
|
||||
}
|
||||
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
bool is_typeless, bool is_ld64, int kind, int insn_idx)
|
||||
bool is_typeless, int kind, int insn_idx)
|
||||
{
|
||||
struct ksym_relo_desc *relo;
|
||||
|
||||
@@ -608,7 +574,6 @@ void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
relo->name = name;
|
||||
relo->is_weak = is_weak;
|
||||
relo->is_typeless = is_typeless;
|
||||
relo->is_ld64 = is_ld64;
|
||||
relo->kind = kind;
|
||||
relo->insn_idx = insn_idx;
|
||||
gen->relo_cnt++;
|
||||
@@ -621,11 +586,9 @@ static struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_des
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||
kdesc = &gen->ksyms[i];
|
||||
if (kdesc->kind == relo->kind && kdesc->is_ld64 == relo->is_ld64 &&
|
||||
!strcmp(kdesc->name, relo->name)) {
|
||||
kdesc->ref++;
|
||||
return kdesc;
|
||||
if (!strcmp(gen->ksyms[i].name, relo->name)) {
|
||||
gen->ksyms[i].ref++;
|
||||
return &gen->ksyms[i];
|
||||
}
|
||||
}
|
||||
kdesc = libbpf_reallocarray(gen->ksyms, gen->nr_ksyms + 1, sizeof(*kdesc));
|
||||
@@ -640,7 +603,6 @@ static struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_des
|
||||
kdesc->ref = 1;
|
||||
kdesc->off = 0;
|
||||
kdesc->insn = 0;
|
||||
kdesc->is_ld64 = relo->is_ld64;
|
||||
return kdesc;
|
||||
}
|
||||
|
||||
@@ -737,17 +699,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo
|
||||
/* obtain fd in BPF_REG_9 */
|
||||
emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7));
|
||||
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
|
||||
/* load fd_array slot pointer */
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||
0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
|
||||
/* store BTF fd in slot, 0 for vmlinux */
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
|
||||
/* jump to insn[insn_idx].off store if fd denotes module BTF */
|
||||
/* jump to fd_array store if fd denotes module BTF */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2));
|
||||
/* set the default value for off */
|
||||
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0));
|
||||
/* skip BTF fd store for vmlinux BTF */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
|
||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 4));
|
||||
/* load fd_array slot pointer */
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||
0, 0, 0, blob_fd_array_off(gen, btf_fd_idx)));
|
||||
/* store BTF fd in slot */
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0));
|
||||
/* store index into insn[insn_idx].off */
|
||||
emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx));
|
||||
log:
|
||||
@@ -818,12 +780,12 @@ log:
|
||||
emit_ksym_relo_log(gen, relo, kdesc->ref);
|
||||
}
|
||||
|
||||
static __u32 src_reg_mask(struct bpf_gen *gen)
|
||||
static __u32 src_reg_mask(void)
|
||||
{
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD) /* src_reg,dst_reg,... */
|
||||
return gen->swapped_endian ? 0xf0 : 0x0f;
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD) /* dst_reg,src_reg,... */
|
||||
return gen->swapped_endian ? 0x0f : 0xf0;
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
return 0x0f; /* src_reg,dst_reg,... */
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
return 0xf0; /* dst_reg,src_reg,... */
|
||||
#else
|
||||
#error "Unsupported bit endianness, cannot proceed"
|
||||
#endif
|
||||
@@ -842,13 +804,11 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
||||
return;
|
||||
/* try to copy from existing ldimm64 insn */
|
||||
if (kdesc->ref > 1) {
|
||||
move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
|
||||
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
||||
move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
|
||||
kdesc->insn + offsetof(struct bpf_insn, imm));
|
||||
/* jump over src_reg adjustment if imm (btf_id) is not 0, reuse BPF_REG_0 from move_blob2blob
|
||||
* If btf_id is zero, clear BPF_PSEUDO_BTF_ID flag in src_reg of ld_imm64 insn
|
||||
*/
|
||||
move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
|
||||
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
||||
/* jump over src_reg adjustment if imm is not 0, reuse BPF_REG_0 from move_blob2blob */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 3));
|
||||
goto clear_src_reg;
|
||||
}
|
||||
@@ -871,10 +831,10 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7,
|
||||
sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
|
||||
/* skip src_reg adjustment */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 3));
|
||||
emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
|
||||
clear_src_reg:
|
||||
/* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */
|
||||
reg_mask = src_reg_mask(gen);
|
||||
reg_mask = src_reg_mask();
|
||||
emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code)));
|
||||
emit(gen, BPF_ALU32_IMM(BPF_AND, BPF_REG_9, reg_mask));
|
||||
emit(gen, BPF_STX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, offsetofend(struct bpf_insn, code)));
|
||||
@@ -902,17 +862,23 @@ static void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn
|
||||
{
|
||||
int insn;
|
||||
|
||||
pr_debug("gen: emit_relo (%d): %s at %d %s\n",
|
||||
relo->kind, relo->name, relo->insn_idx, relo->is_ld64 ? "ld64" : "call");
|
||||
pr_debug("gen: emit_relo (%d): %s at %d\n", relo->kind, relo->name, relo->insn_idx);
|
||||
insn = insns + sizeof(struct bpf_insn) * relo->insn_idx;
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn));
|
||||
if (relo->is_ld64) {
|
||||
switch (relo->kind) {
|
||||
case BTF_KIND_VAR:
|
||||
if (relo->is_typeless)
|
||||
emit_relo_ksym_typeless(gen, relo, insn);
|
||||
else
|
||||
emit_relo_ksym_btf(gen, relo, insn);
|
||||
} else {
|
||||
break;
|
||||
case BTF_KIND_FUNC:
|
||||
emit_relo_kfunc_btf(gen, relo, insn);
|
||||
break;
|
||||
default:
|
||||
pr_warn("Unknown relocation kind '%d'\n", relo->kind);
|
||||
gen->error = -EDOM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,20 +901,18 @@ static void cleanup_core_relo(struct bpf_gen *gen)
|
||||
|
||||
static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||
{
|
||||
struct ksym_desc *kdesc;
|
||||
int i, insn;
|
||||
|
||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||
kdesc = &gen->ksyms[i];
|
||||
/* only close fds for typed ksyms and kfuncs */
|
||||
if (kdesc->is_ld64 && !kdesc->typeless) {
|
||||
if (gen->ksyms[i].kind == BTF_KIND_VAR && !gen->ksyms[i].typeless) {
|
||||
/* close fd recorded in insn[insn_idx + 1].imm */
|
||||
insn = kdesc->insn;
|
||||
insn = gen->ksyms[i].insn;
|
||||
insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm);
|
||||
emit_sys_close_blob(gen, insn);
|
||||
} else if (!kdesc->is_ld64) {
|
||||
emit_sys_close_blob(gen, blob_fd_array_off(gen, kdesc->off));
|
||||
if (kdesc->off < MAX_FD_ARRAY_SZ)
|
||||
} else if (gen->ksyms[i].kind == BTF_KIND_FUNC) {
|
||||
emit_sys_close_blob(gen, blob_fd_array_off(gen, gen->ksyms[i].off));
|
||||
if (gen->ksyms[i].off < MAX_FD_ARRAY_SZ)
|
||||
gen->nr_fd_array--;
|
||||
}
|
||||
}
|
||||
@@ -965,94 +929,48 @@ static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||
cleanup_core_relo(gen);
|
||||
}
|
||||
|
||||
/* Convert func, line, and core relo info blobs to target endianness */
|
||||
static void info_blob_bswap(struct bpf_gen *gen, int func_info, int line_info,
|
||||
int core_relos, struct bpf_prog_load_opts *load_attr)
|
||||
{
|
||||
struct bpf_func_info *fi = gen->data_start + func_info;
|
||||
struct bpf_line_info *li = gen->data_start + line_info;
|
||||
struct bpf_core_relo *cr = gen->data_start + core_relos;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < load_attr->func_info_cnt; i++)
|
||||
bpf_func_info_bswap(fi++);
|
||||
|
||||
for (i = 0; i < load_attr->line_info_cnt; i++)
|
||||
bpf_line_info_bswap(li++);
|
||||
|
||||
for (i = 0; i < gen->core_relo_cnt; i++)
|
||||
bpf_core_relo_bswap(cr++);
|
||||
}
|
||||
|
||||
void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||
enum bpf_prog_type prog_type, const char *prog_name,
|
||||
const char *license, struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *load_attr, int prog_idx)
|
||||
{
|
||||
int func_info_tot_sz = load_attr->func_info_cnt *
|
||||
load_attr->func_info_rec_size;
|
||||
int line_info_tot_sz = load_attr->line_info_cnt *
|
||||
load_attr->line_info_rec_size;
|
||||
int core_relo_tot_sz = gen->core_relo_cnt *
|
||||
sizeof(struct bpf_core_relo);
|
||||
int prog_load_attr, license_off, insns_off, func_info, line_info, core_relos;
|
||||
int attr_size = offsetofend(union bpf_attr, core_relo_rec_size);
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
pr_debug("gen: prog_load: type %d insns_cnt %zd progi_idx %d\n",
|
||||
prog_type, insn_cnt, prog_idx);
|
||||
/* add license string to blob of bytes */
|
||||
license_off = add_data(gen, license, strlen(license) + 1);
|
||||
/* add insns to blob of bytes */
|
||||
insns_off = add_data(gen, insns, insn_cnt * sizeof(struct bpf_insn));
|
||||
pr_debug("gen: prog_load: prog_idx %d type %d insn off %d insns_cnt %zd license off %d\n",
|
||||
prog_idx, prog_type, insns_off, insn_cnt, license_off);
|
||||
|
||||
/* convert blob insns to target endianness */
|
||||
if (gen->swapped_endian) {
|
||||
struct bpf_insn *insn = gen->data_start + insns_off;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++)
|
||||
bpf_insn_bswap(insn);
|
||||
}
|
||||
|
||||
attr.prog_type = tgt_endian(prog_type);
|
||||
attr.expected_attach_type = tgt_endian(load_attr->expected_attach_type);
|
||||
attr.attach_btf_id = tgt_endian(load_attr->attach_btf_id);
|
||||
attr.prog_ifindex = tgt_endian(load_attr->prog_ifindex);
|
||||
attr.prog_type = prog_type;
|
||||
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||
attr.kern_version = 0;
|
||||
attr.insn_cnt = tgt_endian((__u32)insn_cnt);
|
||||
attr.prog_flags = tgt_endian(load_attr->prog_flags);
|
||||
attr.insn_cnt = (__u32)insn_cnt;
|
||||
attr.prog_flags = load_attr->prog_flags;
|
||||
|
||||
attr.func_info_rec_size = tgt_endian(load_attr->func_info_rec_size);
|
||||
attr.func_info_cnt = tgt_endian(load_attr->func_info_cnt);
|
||||
func_info = add_data(gen, load_attr->func_info, func_info_tot_sz);
|
||||
pr_debug("gen: prog_load: func_info: off %d cnt %d rec size %d\n",
|
||||
func_info, load_attr->func_info_cnt,
|
||||
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;
|
||||
func_info = add_data(gen, load_attr->func_info,
|
||||
attr.func_info_cnt * attr.func_info_rec_size);
|
||||
|
||||
attr.line_info_rec_size = tgt_endian(load_attr->line_info_rec_size);
|
||||
attr.line_info_cnt = tgt_endian(load_attr->line_info_cnt);
|
||||
line_info = add_data(gen, load_attr->line_info, line_info_tot_sz);
|
||||
pr_debug("gen: prog_load: line_info: off %d cnt %d rec size %d\n",
|
||||
line_info, load_attr->line_info_cnt,
|
||||
load_attr->line_info_rec_size);
|
||||
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||
attr.line_info_cnt = load_attr->line_info_cnt;
|
||||
line_info = add_data(gen, load_attr->line_info,
|
||||
attr.line_info_cnt * attr.line_info_rec_size);
|
||||
|
||||
attr.core_relo_rec_size = tgt_endian((__u32)sizeof(struct bpf_core_relo));
|
||||
attr.core_relo_cnt = tgt_endian(gen->core_relo_cnt);
|
||||
core_relos = add_data(gen, gen->core_relos, core_relo_tot_sz);
|
||||
pr_debug("gen: prog_load: core_relos: off %d cnt %d rec size %zd\n",
|
||||
core_relos, gen->core_relo_cnt,
|
||||
sizeof(struct bpf_core_relo));
|
||||
|
||||
/* convert all info blobs to target endianness */
|
||||
if (gen->swapped_endian)
|
||||
info_blob_bswap(gen, func_info, line_info, core_relos, load_attr);
|
||||
attr.core_relo_rec_size = sizeof(struct bpf_core_relo);
|
||||
attr.core_relo_cnt = gen->core_relo_cnt;
|
||||
core_relos = add_data(gen, gen->core_relos,
|
||||
attr.core_relo_cnt * attr.core_relo_rec_size);
|
||||
|
||||
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
|
||||
prog_load_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: prog_load: attr: off %d size %d\n",
|
||||
prog_load_attr, attr_size);
|
||||
|
||||
/* populate union bpf_attr with a pointer to license */
|
||||
emit_rel_store(gen, attr_field(prog_load_attr, license), license_off);
|
||||
@@ -1120,6 +1038,7 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
|
||||
int zero = 0;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
pr_debug("gen: map_update_elem: idx %d\n", map_idx);
|
||||
|
||||
value = add_data(gen, pvalue, value_size);
|
||||
key = add_data(gen, &zero, sizeof(zero));
|
||||
@@ -1147,8 +1066,6 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
|
||||
emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
|
||||
|
||||
map_update_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: map_update_elem: idx %d, value: off %d size %d, attr: off %d size %d\n",
|
||||
map_idx, value, value_size, map_update_attr, attr_size);
|
||||
move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4,
|
||||
blob_fd_array_off(gen, map_idx));
|
||||
emit_rel_store(gen, attr_field(map_update_attr, key), key);
|
||||
@@ -1165,16 +1082,14 @@ void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int slo
|
||||
int attr_size = offsetofend(union bpf_attr, flags);
|
||||
int map_update_attr, key;
|
||||
union bpf_attr attr;
|
||||
int tgt_slot;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
pr_debug("gen: populate_outer_map: outer %d key %d inner %d\n",
|
||||
outer_map_idx, slot, inner_map_idx);
|
||||
|
||||
tgt_slot = tgt_endian(slot);
|
||||
key = add_data(gen, &tgt_slot, sizeof(tgt_slot));
|
||||
key = add_data(gen, &slot, sizeof(slot));
|
||||
|
||||
map_update_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: populate_outer_map: outer %d key %d inner %d, attr: off %d size %d\n",
|
||||
outer_map_idx, slot, inner_map_idx, map_update_attr, attr_size);
|
||||
move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4,
|
||||
blob_fd_array_off(gen, outer_map_idx));
|
||||
emit_rel_store(gen, attr_field(map_update_attr, key), key);
|
||||
@@ -1195,9 +1110,8 @@ void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx)
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_size);
|
||||
pr_debug("gen: map_freeze: idx %d\n", map_idx);
|
||||
map_freeze_attr = add_data(gen, &attr, attr_size);
|
||||
pr_debug("gen: map_freeze: idx %d, attr: off %d size %d\n",
|
||||
map_idx, map_freeze_attr, attr_size);
|
||||
move_blob2blob(gen, attr_field(map_freeze_attr, map_fd), 4,
|
||||
blob_fd_array_off(gen, map_idx));
|
||||
/* emit MAP_FREEZE command */
|
||||
|
||||
@@ -128,7 +128,7 @@ static int hashmap_grow(struct hashmap *map)
|
||||
}
|
||||
|
||||
static bool hashmap_find_entry(const struct hashmap *map,
|
||||
const long key, size_t hash,
|
||||
const void *key, size_t hash,
|
||||
struct hashmap_entry ***pprev,
|
||||
struct hashmap_entry **entry)
|
||||
{
|
||||
@@ -151,18 +151,18 @@ static bool hashmap_find_entry(const struct hashmap *map,
|
||||
return false;
|
||||
}
|
||||
|
||||
int hashmap_insert(struct hashmap *map, long key, long value,
|
||||
enum hashmap_insert_strategy strategy,
|
||||
long *old_key, long *old_value)
|
||||
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
||||
enum hashmap_insert_strategy strategy,
|
||||
const void **old_key, void **old_value)
|
||||
{
|
||||
struct hashmap_entry *entry;
|
||||
size_t h;
|
||||
int err;
|
||||
|
||||
if (old_key)
|
||||
*old_key = 0;
|
||||
*old_key = NULL;
|
||||
if (old_value)
|
||||
*old_value = 0;
|
||||
*old_value = NULL;
|
||||
|
||||
h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
|
||||
if (strategy != HASHMAP_APPEND &&
|
||||
@@ -203,7 +203,7 @@ int hashmap_insert(struct hashmap *map, long key, long value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hashmap_find(const struct hashmap *map, long key, long *value)
|
||||
bool hashmap__find(const struct hashmap *map, const void *key, void **value)
|
||||
{
|
||||
struct hashmap_entry *entry;
|
||||
size_t h;
|
||||
@@ -217,8 +217,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hashmap_delete(struct hashmap *map, long key,
|
||||
long *old_key, long *old_value)
|
||||
bool hashmap__delete(struct hashmap *map, const void *key,
|
||||
const void **old_key, void **old_value)
|
||||
{
|
||||
struct hashmap_entry **pprev, *entry;
|
||||
size_t h;
|
||||
|
||||
121
src/hashmap.h
121
src/hashmap.h
@@ -40,32 +40,12 @@ static inline size_t str_hash(const char *s)
|
||||
return h;
|
||||
}
|
||||
|
||||
typedef size_t (*hashmap_hash_fn)(long key, void *ctx);
|
||||
typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx);
|
||||
typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);
|
||||
typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx);
|
||||
|
||||
/*
|
||||
* Hashmap interface is polymorphic, keys and values could be either
|
||||
* long-sized integers or pointers, this is achieved as follows:
|
||||
* - interface functions that operate on keys and values are hidden
|
||||
* behind auxiliary macros, e.g. hashmap_insert <-> hashmap__insert;
|
||||
* - these auxiliary macros cast the key and value parameters as
|
||||
* long or long *, so the user does not have to specify the casts explicitly;
|
||||
* - for pointer parameters (e.g. old_key) the size of the pointed
|
||||
* type is verified by hashmap_cast_ptr using _Static_assert;
|
||||
* - when iterating using hashmap__for_each_* forms
|
||||
* hasmap_entry->key should be used for integer keys and
|
||||
* hasmap_entry->pkey should be used for pointer keys,
|
||||
* same goes for values.
|
||||
*/
|
||||
struct hashmap_entry {
|
||||
union {
|
||||
long key;
|
||||
const void *pkey;
|
||||
};
|
||||
union {
|
||||
long value;
|
||||
void *pvalue;
|
||||
};
|
||||
const void *key;
|
||||
void *value;
|
||||
struct hashmap_entry *next;
|
||||
};
|
||||
|
||||
@@ -80,6 +60,16 @@ struct hashmap {
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
#define HASHMAP_INIT(hash_fn, equal_fn, ctx) { \
|
||||
.hash_fn = (hash_fn), \
|
||||
.equal_fn = (equal_fn), \
|
||||
.ctx = (ctx), \
|
||||
.buckets = NULL, \
|
||||
.cap = 0, \
|
||||
.cap_bits = 0, \
|
||||
.sz = 0, \
|
||||
}
|
||||
|
||||
void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
|
||||
hashmap_equal_fn equal_fn, void *ctx);
|
||||
struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
|
||||
@@ -112,13 +102,6 @@ enum hashmap_insert_strategy {
|
||||
HASHMAP_APPEND,
|
||||
};
|
||||
|
||||
#define hashmap_cast_ptr(p) ({ \
|
||||
_Static_assert((__builtin_constant_p((p)) ? (p) == NULL : 0) || \
|
||||
sizeof(*(p)) == sizeof(long), \
|
||||
#p " pointee should be a long-sized integer or a pointer"); \
|
||||
(long *)(p); \
|
||||
})
|
||||
|
||||
/*
|
||||
* hashmap__insert() adds key/value entry w/ various semantics, depending on
|
||||
* provided strategy value. If a given key/value pair replaced already
|
||||
@@ -126,38 +109,42 @@ enum hashmap_insert_strategy {
|
||||
* through old_key and old_value to allow calling code do proper memory
|
||||
* management.
|
||||
*/
|
||||
int hashmap_insert(struct hashmap *map, long key, long value,
|
||||
enum hashmap_insert_strategy strategy,
|
||||
long *old_key, long *old_value);
|
||||
int hashmap__insert(struct hashmap *map, const void *key, void *value,
|
||||
enum hashmap_insert_strategy strategy,
|
||||
const void **old_key, void **old_value);
|
||||
|
||||
#define hashmap__insert(map, key, value, strategy, old_key, old_value) \
|
||||
hashmap_insert((map), (long)(key), (long)(value), (strategy), \
|
||||
hashmap_cast_ptr(old_key), \
|
||||
hashmap_cast_ptr(old_value))
|
||||
static inline int hashmap__add(struct hashmap *map,
|
||||
const void *key, void *value)
|
||||
{
|
||||
return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL);
|
||||
}
|
||||
|
||||
#define hashmap__add(map, key, value) \
|
||||
hashmap__insert((map), (key), (value), HASHMAP_ADD, NULL, NULL)
|
||||
static inline int hashmap__set(struct hashmap *map,
|
||||
const void *key, void *value,
|
||||
const void **old_key, void **old_value)
|
||||
{
|
||||
return hashmap__insert(map, key, value, HASHMAP_SET,
|
||||
old_key, old_value);
|
||||
}
|
||||
|
||||
#define hashmap__set(map, key, value, old_key, old_value) \
|
||||
hashmap__insert((map), (key), (value), HASHMAP_SET, (old_key), (old_value))
|
||||
static inline int hashmap__update(struct hashmap *map,
|
||||
const void *key, void *value,
|
||||
const void **old_key, void **old_value)
|
||||
{
|
||||
return hashmap__insert(map, key, value, HASHMAP_UPDATE,
|
||||
old_key, old_value);
|
||||
}
|
||||
|
||||
#define hashmap__update(map, key, value, old_key, old_value) \
|
||||
hashmap__insert((map), (key), (value), HASHMAP_UPDATE, (old_key), (old_value))
|
||||
static inline int hashmap__append(struct hashmap *map,
|
||||
const void *key, void *value)
|
||||
{
|
||||
return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL);
|
||||
}
|
||||
|
||||
#define hashmap__append(map, key, value) \
|
||||
hashmap__insert((map), (key), (value), HASHMAP_APPEND, NULL, NULL)
|
||||
bool hashmap__delete(struct hashmap *map, const void *key,
|
||||
const void **old_key, void **old_value);
|
||||
|
||||
bool hashmap_delete(struct hashmap *map, long key, long *old_key, long *old_value);
|
||||
|
||||
#define hashmap__delete(map, key, old_key, old_value) \
|
||||
hashmap_delete((map), (long)(key), \
|
||||
hashmap_cast_ptr(old_key), \
|
||||
hashmap_cast_ptr(old_value))
|
||||
|
||||
bool hashmap_find(const struct hashmap *map, long key, long *value);
|
||||
|
||||
#define hashmap__find(map, key, value) \
|
||||
hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
|
||||
bool hashmap__find(const struct hashmap *map, const void *key, void **value);
|
||||
|
||||
/*
|
||||
* hashmap__for_each_entry - iterate over all entries in hashmap
|
||||
@@ -166,8 +153,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value);
|
||||
* @bkt: integer used as a bucket loop cursor
|
||||
*/
|
||||
#define hashmap__for_each_entry(map, cur, bkt) \
|
||||
for (bkt = 0; bkt < (map)->cap; bkt++) \
|
||||
for (cur = (map)->buckets[bkt]; cur; cur = cur->next)
|
||||
for (bkt = 0; bkt < map->cap; bkt++) \
|
||||
for (cur = map->buckets[bkt]; cur; cur = cur->next)
|
||||
|
||||
/*
|
||||
* hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe
|
||||
@@ -178,8 +165,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value);
|
||||
* @bkt: integer used as a bucket loop cursor
|
||||
*/
|
||||
#define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \
|
||||
for (bkt = 0; bkt < (map)->cap; bkt++) \
|
||||
for (cur = (map)->buckets[bkt]; \
|
||||
for (bkt = 0; bkt < map->cap; bkt++) \
|
||||
for (cur = map->buckets[bkt]; \
|
||||
cur && ({tmp = cur->next; true; }); \
|
||||
cur = tmp)
|
||||
|
||||
@@ -190,19 +177,19 @@ bool hashmap_find(const struct hashmap *map, long key, long *value);
|
||||
* @key: key to iterate entries for
|
||||
*/
|
||||
#define hashmap__for_each_key_entry(map, cur, _key) \
|
||||
for (cur = (map)->buckets \
|
||||
? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \
|
||||
for (cur = map->buckets \
|
||||
? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \
|
||||
: NULL; \
|
||||
cur; \
|
||||
cur = cur->next) \
|
||||
if ((map)->equal_fn(cur->key, (_key), (map)->ctx))
|
||||
if (map->equal_fn(cur->key, (_key), map->ctx))
|
||||
|
||||
#define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \
|
||||
for (cur = (map)->buckets \
|
||||
? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \
|
||||
for (cur = map->buckets \
|
||||
? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \
|
||||
: NULL; \
|
||||
cur && ({ tmp = cur->next; true; }); \
|
||||
cur = tmp) \
|
||||
if ((map)->equal_fn(cur->key, (_key), (map)->ctx))
|
||||
if (map->equal_fn(cur->key, (_key), map->ctx))
|
||||
|
||||
#endif /* __LIBBPF_HASHMAP_H */
|
||||
|
||||
4557
src/libbpf.c
4557
src/libbpf.c
File diff suppressed because it is too large
Load Diff
485
src/libbpf.h
485
src/libbpf.h
@@ -96,17 +96,6 @@ enum libbpf_print_level {
|
||||
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
||||
const char *, va_list ap);
|
||||
|
||||
/**
|
||||
* @brief **libbpf_set_print()** sets user-provided log callback function to
|
||||
* be used for libbpf warnings and informational messages. If the user callback
|
||||
* is not set, messages are logged to stderr by default. The verbosity of these
|
||||
* messages can be controlled by setting the environment variable
|
||||
* LIBBPF_LOG_LEVEL to either warn, info, or debug.
|
||||
* @param fn The log print function. If NULL, libbpf won't print anything.
|
||||
* @return Pointer to old print function.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*/
|
||||
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
|
||||
|
||||
/* Hide internal to user */
|
||||
@@ -152,7 +141,7 @@ struct bpf_object_open_opts {
|
||||
* log_buf and log_level settings.
|
||||
*
|
||||
* If specified, this log buffer will be passed for:
|
||||
* - each BPF progral load (BPF_PROG_LOAD) attempt, unless overridden
|
||||
* - each BPF progral load (BPF_PROG_LOAD) attempt, unless overriden
|
||||
* with bpf_program__set_log() on per-program level, to get
|
||||
* BPF verifier log output.
|
||||
* - during BPF object's BTF load into kernel (BPF_BTF_LOAD) to get
|
||||
@@ -180,38 +169,11 @@ struct bpf_object_open_opts {
|
||||
* logs through its print callback.
|
||||
*/
|
||||
__u32 kernel_log_level;
|
||||
/* Path to BPF FS mount point to derive BPF token from.
|
||||
*
|
||||
* Created BPF token will be used for all bpf() syscall operations
|
||||
* that accept BPF token (e.g., map creation, BTF and program loads,
|
||||
* etc) automatically within instantiated BPF object.
|
||||
*
|
||||
* If bpf_token_path is not specified, libbpf will consult
|
||||
* LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will be
|
||||
* taken as a value of bpf_token_path option and will force libbpf to
|
||||
* either create BPF token from provided custom BPF FS path, or will
|
||||
* disable implicit BPF token creation, if envvar value is an empty
|
||||
* string. bpf_token_path overrides LIBBPF_BPF_TOKEN_PATH, if both are
|
||||
* set at the same time.
|
||||
*
|
||||
* Setting bpf_token_path option to empty string disables libbpf's
|
||||
* automatic attempt to create BPF token from default BPF FS mount
|
||||
* point (/sys/fs/bpf), in case this default behavior is undesirable.
|
||||
*/
|
||||
const char *bpf_token_path;
|
||||
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_object_open_opts__last_field bpf_token_path
|
||||
#define bpf_object_open_opts__last_field kernel_log_level
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__open()** creates a bpf_object by opening
|
||||
* the BPF ELF object file pointed to by the passed path and loading it
|
||||
* into memory.
|
||||
* @param path BPF object file path.
|
||||
* @return pointer to the new bpf_object; or NULL is returned on error,
|
||||
* error code is stored in errno
|
||||
*/
|
||||
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
||||
|
||||
/**
|
||||
@@ -241,59 +203,16 @@ 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);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__prepare()** prepares BPF object for loading:
|
||||
* performs ELF processing, relocations, prepares final state of BPF program
|
||||
* instructions (accessible with bpf_program__insns()), creates and
|
||||
* (potentially) pins maps. Leaves BPF object in the state ready for program
|
||||
* loading.
|
||||
* @param obj Pointer to a valid BPF object instance returned by
|
||||
* **bpf_object__open*()** API
|
||||
* @return 0, on success; negative error code, otherwise, error code is
|
||||
* stored in errno
|
||||
*/
|
||||
int bpf_object__prepare(struct bpf_object *obj);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__load()** loads BPF object into kernel.
|
||||
* @param obj Pointer to a valid BPF object instance returned by
|
||||
* **bpf_object__open*()** APIs
|
||||
* @return 0, on success; negative error code, otherwise, error code is
|
||||
* stored in errno
|
||||
*/
|
||||
/* Load/unload object into/from kernel */
|
||||
LIBBPF_API int bpf_object__load(struct bpf_object *obj);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__close()** closes a BPF object and releases all
|
||||
* resources.
|
||||
* @param obj Pointer to a valid BPF object
|
||||
*/
|
||||
LIBBPF_API void bpf_object__close(struct bpf_object *obj);
|
||||
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__pin_maps()** pins each map contained within
|
||||
* the BPF object at the passed directory.
|
||||
* @param obj Pointer to a valid BPF object
|
||||
* @param path A directory where maps should be pinned.
|
||||
* @return 0, on success; negative error code, otherwise
|
||||
*
|
||||
* If `path` is NULL `bpf_map__pin` (which is being used on each map)
|
||||
* will use the pin_path attribute of each map. In this case, maps that
|
||||
* don't have a pin_path set will be ignored.
|
||||
/* pin_maps and unpin_maps can both be called with a NULL path, in which case
|
||||
* they will use the pin_path attribute of each map (and ignore all maps that
|
||||
* don't have a pin_path set).
|
||||
*/
|
||||
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__unpin_maps()** unpins each map contained within
|
||||
* the BPF object found in the passed directory.
|
||||
* @param obj Pointer to a valid BPF object
|
||||
* @param path A directory where pinned maps should be searched for.
|
||||
* @return 0, on success; negative error code, otherwise
|
||||
*
|
||||
* If `path` is NULL `bpf_map__unpin` (which is being used on each map)
|
||||
* will use the pin_path attribute of each map. In this case, maps that
|
||||
* don't have a pin_path set will be ignored.
|
||||
*/
|
||||
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||
@@ -301,20 +220,11 @@ LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||
LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
||||
LIBBPF_API int bpf_object__unpin(struct bpf_object *object, const char *path);
|
||||
|
||||
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
||||
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
||||
LIBBPF_API int bpf_object__set_kversion(struct bpf_object *obj, __u32 kern_version);
|
||||
|
||||
/**
|
||||
* @brief **bpf_object__token_fd** is an accessor for BPF token FD associated
|
||||
* with BPF object.
|
||||
* @param obj Pointer to a valid BPF object
|
||||
* @return BPF token FD or -1, if it wasn't set
|
||||
*/
|
||||
LIBBPF_API int bpf_object__token_fd(const struct bpf_object *obj);
|
||||
|
||||
struct btf;
|
||||
LIBBPF_API struct btf *bpf_object__btf(const struct bpf_object *obj);
|
||||
LIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj);
|
||||
@@ -476,7 +386,7 @@ LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
||||
/**
|
||||
* @brief **bpf_program__attach()** is a generic function for attaching
|
||||
* a BPF program based on auto-detection of program type, attach type,
|
||||
* and extra parameters, where applicable.
|
||||
* and extra paremeters, where applicable.
|
||||
*
|
||||
* @param prog BPF program to attach
|
||||
* @return Reference to the newly created BPF link; or NULL is returned on error,
|
||||
@@ -493,15 +403,12 @@ LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach(const struct bpf_program *prog);
|
||||
|
||||
struct bpf_perf_event_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||
__u64 bpf_cookie;
|
||||
/* don't use BPF link when attach BPF program */
|
||||
bool force_ioctl_attach;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_perf_event_opts__last_field force_ioctl_attach
|
||||
#define bpf_perf_event_opts__last_field bpf_cookie
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_perf_event(const struct bpf_program *prog, int pfd);
|
||||
@@ -510,25 +417,8 @@ LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd,
|
||||
const struct bpf_perf_event_opts *opts);
|
||||
|
||||
/**
|
||||
* enum probe_attach_mode - the mode to attach kprobe/uprobe
|
||||
*
|
||||
* force libbpf to attach kprobe/uprobe in specific mode, -ENOTSUP will
|
||||
* be returned if it is not supported by the kernel.
|
||||
*/
|
||||
enum probe_attach_mode {
|
||||
/* attach probe in latest supported mode by kernel */
|
||||
PROBE_ATTACH_MODE_DEFAULT = 0,
|
||||
/* attach probe in legacy mode, using debugfs/tracefs */
|
||||
PROBE_ATTACH_MODE_LEGACY,
|
||||
/* create perf event with perf_event_open() syscall */
|
||||
PROBE_ATTACH_MODE_PERF,
|
||||
/* attach probe with BPF link */
|
||||
PROBE_ATTACH_MODE_LINK,
|
||||
};
|
||||
|
||||
struct bpf_kprobe_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||
__u64 bpf_cookie;
|
||||
@@ -536,11 +426,9 @@ struct bpf_kprobe_opts {
|
||||
size_t offset;
|
||||
/* kprobe is return probe */
|
||||
bool retprobe;
|
||||
/* kprobe attach mode */
|
||||
enum probe_attach_mode attach_mode;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_kprobe_opts__last_field attach_mode
|
||||
#define bpf_kprobe_opts__last_field retprobe
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_kprobe(const struct bpf_program *prog, bool retprobe,
|
||||
@@ -563,75 +451,18 @@ struct bpf_kprobe_multi_opts {
|
||||
size_t cnt;
|
||||
/* create return kprobes */
|
||||
bool retprobe;
|
||||
/* create session kprobes */
|
||||
bool session;
|
||||
/* enforce unique match */
|
||||
bool unique_match;
|
||||
size_t :0;
|
||||
};
|
||||
|
||||
#define bpf_kprobe_multi_opts__last_field unique_match
|
||||
#define bpf_kprobe_multi_opts__last_field retprobe
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
||||
const char *pattern,
|
||||
const struct bpf_kprobe_multi_opts *opts);
|
||||
|
||||
struct bpf_uprobe_multi_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
/* array of function symbols to attach to */
|
||||
const char **syms;
|
||||
/* array of function addresses to attach to */
|
||||
const unsigned long *offsets;
|
||||
/* optional, array of associated ref counter offsets */
|
||||
const unsigned long *ref_ctr_offsets;
|
||||
/* optional, array of associated BPF cookies */
|
||||
const __u64 *cookies;
|
||||
/* number of elements in syms/addrs/cookies arrays */
|
||||
size_t cnt;
|
||||
/* create return uprobes */
|
||||
bool retprobe;
|
||||
/* create session kprobes */
|
||||
bool session;
|
||||
size_t :0;
|
||||
};
|
||||
|
||||
#define bpf_uprobe_multi_opts__last_field session
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program
|
||||
* to multiple uprobes with uprobe_multi link.
|
||||
*
|
||||
* User can specify 2 mutually exclusive set of inputs:
|
||||
*
|
||||
* 1) use only path/func_pattern/pid arguments
|
||||
*
|
||||
* 2) use path/pid with allowed combinations of
|
||||
* syms/offsets/ref_ctr_offsets/cookies/cnt
|
||||
*
|
||||
* - syms and offsets are mutually exclusive
|
||||
* - ref_ctr_offsets and cookies are optional
|
||||
*
|
||||
*
|
||||
* @param prog BPF program to attach
|
||||
* @param pid Process ID to attach the uprobe to, 0 for self (own process),
|
||||
* -1 for all processes
|
||||
* @param binary_path Path to binary
|
||||
* @param func_pattern Regular expression to specify functions to attach
|
||||
* BPF program to
|
||||
* @param opts Additional options (see **struct bpf_uprobe_multi_opts**)
|
||||
* @return 0, on success; negative error code, otherwise
|
||||
*/
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
|
||||
pid_t pid,
|
||||
const char *binary_path,
|
||||
const char *func_pattern,
|
||||
const struct bpf_uprobe_multi_opts *opts);
|
||||
|
||||
struct bpf_ksyscall_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||
__u64 bpf_cookie;
|
||||
@@ -677,7 +508,7 @@ bpf_program__attach_ksyscall(const struct bpf_program *prog,
|
||||
const struct bpf_ksyscall_opts *opts);
|
||||
|
||||
struct bpf_uprobe_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* offset of kernel reference counted USDT semaphore, added in
|
||||
* a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
||||
@@ -695,16 +526,14 @@ struct bpf_uprobe_opts {
|
||||
* binary_path.
|
||||
*/
|
||||
const char *func_name;
|
||||
/* uprobe attach mode */
|
||||
enum probe_attach_mode attach_mode;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_uprobe_opts__last_field attach_mode
|
||||
#define bpf_uprobe_opts__last_field func_name
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__attach_uprobe()** attaches a BPF program
|
||||
* to the userspace function which is found by binary path and
|
||||
* offset. You can optionally specify a particular process to attach
|
||||
* offset. You can optionally specify a particular proccess to attach
|
||||
* to. You can also optionally attach the program to the function
|
||||
* exit instead of entry.
|
||||
*
|
||||
@@ -773,7 +602,7 @@ bpf_program__attach_usdt(const struct bpf_program *prog,
|
||||
const struct bpf_usdt_opts *opts);
|
||||
|
||||
struct bpf_tracepoint_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||
__u64 bpf_cookie;
|
||||
@@ -790,20 +619,9 @@ bpf_program__attach_tracepoint_opts(const struct bpf_program *prog,
|
||||
const char *tp_name,
|
||||
const struct bpf_tracepoint_opts *opts);
|
||||
|
||||
struct bpf_raw_tracepoint_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u64 cookie;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_raw_tracepoint_opts__last_field cookie
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_raw_tracepoint(const struct bpf_program *prog,
|
||||
const char *tp_name);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog,
|
||||
const char *tp_name,
|
||||
struct bpf_raw_tracepoint_opts *opts);
|
||||
|
||||
struct bpf_trace_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
@@ -825,62 +643,14 @@ bpf_program__attach_cgroup(const struct bpf_program *prog, int cgroup_fd);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_netns(const struct bpf_program *prog, int netns_fd);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_sockmap(const struct bpf_program *prog, int map_fd);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_xdp(const struct bpf_program *prog, int ifindex);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_freplace(const struct bpf_program *prog,
|
||||
int target_fd, const char *attach_func_name);
|
||||
|
||||
struct bpf_netfilter_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
|
||||
__u32 pf;
|
||||
__u32 hooknum;
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
};
|
||||
#define bpf_netfilter_opts__last_field flags
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_netfilter(const struct bpf_program *prog,
|
||||
const struct bpf_netfilter_opts *opts);
|
||||
|
||||
struct bpf_tcx_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
__u32 flags;
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_tcx_opts__last_field expected_revision
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_tcx(const struct bpf_program *prog, int ifindex,
|
||||
const struct bpf_tcx_opts *opts);
|
||||
|
||||
struct bpf_netkit_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
__u32 flags;
|
||||
__u32 relative_fd;
|
||||
__u32 relative_id;
|
||||
__u64 expected_revision;
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_netkit_opts__last_field expected_revision
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_netkit(const struct bpf_program *prog, int ifindex,
|
||||
const struct bpf_netkit_opts *opts);
|
||||
|
||||
struct bpf_map;
|
||||
|
||||
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_link__update_map(struct bpf_link *link, const struct bpf_map *map);
|
||||
|
||||
struct bpf_iter_attach_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
@@ -940,12 +710,6 @@ LIBBPF_API int bpf_program__set_log_level(struct bpf_program *prog, __u32 log_le
|
||||
LIBBPF_API const char *bpf_program__log_buf(const struct bpf_program *prog, size_t *log_size);
|
||||
LIBBPF_API int bpf_program__set_log_buf(struct bpf_program *prog, char *log_buf, size_t log_size);
|
||||
|
||||
LIBBPF_API struct bpf_func_info *bpf_program__func_info(const struct bpf_program *prog);
|
||||
LIBBPF_API __u32 bpf_program__func_info_cnt(const struct bpf_program *prog);
|
||||
|
||||
LIBBPF_API struct bpf_line_info *bpf_program__line_info(const struct bpf_program *prog);
|
||||
LIBBPF_API __u32 bpf_program__line_info_cnt(const struct bpf_program *prog);
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__set_attach_target()** sets BTF-based attach target
|
||||
* for supported BPF program types:
|
||||
@@ -1009,23 +773,6 @@ bpf_object__prev_map(const struct bpf_object *obj, const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_map__set_autocreate(struct bpf_map *map, bool autocreate);
|
||||
LIBBPF_API bool bpf_map__autocreate(const struct bpf_map *map);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__set_autoattach()** sets whether libbpf has to auto-attach
|
||||
* map during BPF skeleton attach phase.
|
||||
* @param map the BPF map instance
|
||||
* @param autoattach whether to attach map during BPF skeleton attach phase
|
||||
* @return 0 on success; negative error code, otherwise
|
||||
*/
|
||||
LIBBPF_API int bpf_map__set_autoattach(struct bpf_map *map, bool autoattach);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__autoattach()** returns whether BPF map is configured to
|
||||
* auto-attach during BPF skeleton attach phase.
|
||||
* @param map the BPF map instance
|
||||
* @return true if map is set to auto-attach during skeleton attach phase; false, otherwise
|
||||
*/
|
||||
LIBBPF_API bool bpf_map__autoattach(const struct bpf_map *map);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__fd()** gets the file descriptor of the passed
|
||||
* BPF map
|
||||
@@ -1051,22 +798,8 @@ LIBBPF_API int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node);
|
||||
/* get/set map key size */
|
||||
LIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size);
|
||||
/* get map value size */
|
||||
/* get/set map value size */
|
||||
LIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map);
|
||||
/**
|
||||
* @brief **bpf_map__set_value_size()** sets map value size.
|
||||
* @param map the BPF map instance
|
||||
* @return 0, on success; negative error, otherwise
|
||||
*
|
||||
* There is a special case for maps with associated memory-mapped regions, like
|
||||
* the global data section maps (bss, data, rodata). When this function is used
|
||||
* on such a map, the mapped region is resized. Afterward, an attempt is made to
|
||||
* adjust the corresponding BTF info. This attempt is best-effort and can only
|
||||
* succeed if the last variable of the data section map is an array. The array
|
||||
* BTF type is replaced by a new BTF array type with a different length.
|
||||
* Any previously existing pointers returned from bpf_map__initial_value() or
|
||||
* corresponding data section skeleton pointer must be reinitialized.
|
||||
*/
|
||||
LIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size);
|
||||
/* get map key/value BTF type IDs */
|
||||
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
|
||||
@@ -1080,7 +813,7 @@ LIBBPF_API int bpf_map__set_map_extra(struct bpf_map *map, __u64 map_extra);
|
||||
|
||||
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
||||
const void *data, size_t size);
|
||||
LIBBPF_API void *bpf_map__initial_value(const struct bpf_map *map, size_t *psize);
|
||||
LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__is_internal()** tells the caller whether or not the
|
||||
@@ -1090,57 +823,10 @@ LIBBPF_API void *bpf_map__initial_value(const struct bpf_map *map, size_t *psize
|
||||
* @return true, if the map is an internal map; false, otherwise
|
||||
*/
|
||||
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__set_pin_path()** sets the path attribute that tells where the
|
||||
* BPF map should be pinned. This does not actually create the 'pin'.
|
||||
* @param map The bpf_map
|
||||
* @param path The path
|
||||
* @return 0, on success; negative error, otherwise
|
||||
*/
|
||||
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__pin_path()** gets the path attribute that tells where the
|
||||
* BPF map should be pinned.
|
||||
* @param map The bpf_map
|
||||
* @return The path string; which can be NULL
|
||||
*/
|
||||
LIBBPF_API const char *bpf_map__pin_path(const struct bpf_map *map);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__is_pinned()** tells the caller whether or not the
|
||||
* passed map has been pinned via a 'pin' file.
|
||||
* @param map The bpf_map
|
||||
* @return true, if the map is pinned; false, otherwise
|
||||
*/
|
||||
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__pin()** creates a file that serves as a 'pin'
|
||||
* for the BPF map. This increments the reference count on the
|
||||
* BPF map which will keep the BPF map loaded even after the
|
||||
* userspace process which loaded it has exited.
|
||||
* @param map The bpf_map to pin
|
||||
* @param path A file path for the 'pin'
|
||||
* @return 0, on success; negative error, otherwise
|
||||
*
|
||||
* If `path` is NULL the maps `pin_path` attribute will be used. If this is
|
||||
* also NULL, an error will be returned and the map will not be pinned.
|
||||
*/
|
||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map__unpin()** removes the file that serves as a
|
||||
* 'pin' for the BPF map.
|
||||
* @param map The bpf_map to unpin
|
||||
* @param path A file path for the 'pin'
|
||||
* @return 0, on success; negative error, otherwise
|
||||
*
|
||||
* The `path` parameter can be NULL, in which case the `pin_path`
|
||||
* map attribute is unpinned. If both the `path` parameter and
|
||||
* `pin_path` map attribute are set, they must be equal.
|
||||
*/
|
||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||
|
||||
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
||||
@@ -1271,11 +957,9 @@ struct bpf_xdp_query_opts {
|
||||
__u32 hw_prog_id; /* output */
|
||||
__u32 skb_prog_id; /* output */
|
||||
__u8 attach_mode; /* output */
|
||||
__u64 feature_flags; /* output */
|
||||
__u32 xdp_zc_max_segs; /* output */
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_xdp_query_opts__last_field xdp_zc_max_segs
|
||||
#define bpf_xdp_query_opts__last_field attach_mode
|
||||
|
||||
LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags,
|
||||
const struct bpf_xdp_attach_opts *opts);
|
||||
@@ -1329,13 +1013,12 @@ LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,
|
||||
|
||||
/* Ring buffer APIs */
|
||||
struct ring_buffer;
|
||||
struct ring;
|
||||
struct user_ring_buffer;
|
||||
|
||||
typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);
|
||||
|
||||
struct ring_buffer_opts {
|
||||
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||
size_t sz; /* size of this struct, for forward/backward compatiblity */
|
||||
};
|
||||
|
||||
#define ring_buffer_opts__last_field sz
|
||||
@@ -1348,100 +1031,15 @@ LIBBPF_API int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
ring_buffer_sample_fn sample_cb, void *ctx);
|
||||
LIBBPF_API int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms);
|
||||
LIBBPF_API int ring_buffer__consume(struct ring_buffer *rb);
|
||||
LIBBPF_API int ring_buffer__consume_n(struct ring_buffer *rb, size_t n);
|
||||
LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);
|
||||
|
||||
/**
|
||||
* @brief **ring_buffer__ring()** returns the ringbuffer object inside a given
|
||||
* ringbuffer manager representing a single BPF_MAP_TYPE_RINGBUF map instance.
|
||||
*
|
||||
* @param rb A ringbuffer manager object.
|
||||
* @param idx An index into the ringbuffers contained within the ringbuffer
|
||||
* manager object. The index is 0-based and corresponds to the order in which
|
||||
* ring_buffer__add was called.
|
||||
* @return A ringbuffer object on success; NULL and errno set if the index is
|
||||
* invalid.
|
||||
*/
|
||||
LIBBPF_API struct ring *ring_buffer__ring(struct ring_buffer *rb,
|
||||
unsigned int idx);
|
||||
|
||||
/**
|
||||
* @brief **ring__consumer_pos()** returns the current consumer position in the
|
||||
* given ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The current consumer position.
|
||||
*/
|
||||
LIBBPF_API unsigned long ring__consumer_pos(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__producer_pos()** returns the current producer position in the
|
||||
* given ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The current producer position.
|
||||
*/
|
||||
LIBBPF_API unsigned long ring__producer_pos(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__avail_data_size()** returns the number of bytes in the
|
||||
* ringbuffer not yet consumed. This has no locking associated with it, so it
|
||||
* can be inaccurate if operations are ongoing while this is called. However, it
|
||||
* should still show the correct trend over the long-term.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The number of bytes not yet consumed.
|
||||
*/
|
||||
LIBBPF_API size_t ring__avail_data_size(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__size()** returns the total size of the ringbuffer's map data
|
||||
* area (excluding special producer/consumer pages). Effectively this gives the
|
||||
* amount of usable bytes of data inside the ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The total size of the ringbuffer map data area.
|
||||
*/
|
||||
LIBBPF_API size_t ring__size(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__map_fd()** returns the file descriptor underlying the given
|
||||
* ringbuffer.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The underlying ringbuffer file descriptor
|
||||
*/
|
||||
LIBBPF_API int ring__map_fd(const struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__consume()** consumes available ringbuffer data without event
|
||||
* polling.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @return The number of records consumed (or INT_MAX, whichever is less), or
|
||||
* a negative number if any of the callbacks return an error.
|
||||
*/
|
||||
LIBBPF_API int ring__consume(struct ring *r);
|
||||
|
||||
/**
|
||||
* @brief **ring__consume_n()** consumes up to a requested amount of items from
|
||||
* a ringbuffer without event polling.
|
||||
*
|
||||
* @param r A ringbuffer object.
|
||||
* @param n Maximum amount of items to consume.
|
||||
* @return The number of items consumed, or a negative number if any of the
|
||||
* callbacks return an error.
|
||||
*/
|
||||
LIBBPF_API int ring__consume_n(struct ring *r, size_t n);
|
||||
|
||||
struct user_ring_buffer_opts {
|
||||
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||
};
|
||||
|
||||
#define user_ring_buffer_opts__last_field sz
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__new()** creates a new instance of a user ring
|
||||
/* @brief **user_ring_buffer__new()** creates a new instance of a user ring
|
||||
* buffer.
|
||||
*
|
||||
* @param map_fd A file descriptor to a BPF_MAP_TYPE_USER_RINGBUF map.
|
||||
@@ -1452,8 +1050,7 @@ struct user_ring_buffer_opts {
|
||||
LIBBPF_API struct user_ring_buffer *
|
||||
user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__reserve()** reserves a pointer to a sample in the
|
||||
/* @brief **user_ring_buffer__reserve()** reserves a pointer to a sample in the
|
||||
* user ring buffer.
|
||||
* @param rb A pointer to a user ring buffer.
|
||||
* @param size The size of the sample, in bytes.
|
||||
@@ -1473,8 +1070,7 @@ user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts);
|
||||
*/
|
||||
LIBBPF_API void *user_ring_buffer__reserve(struct user_ring_buffer *rb, __u32 size);
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__reserve_blocking()** reserves a record in the
|
||||
/* @brief **user_ring_buffer__reserve_blocking()** reserves a record in the
|
||||
* ring buffer, possibly blocking for up to @timeout_ms until a sample becomes
|
||||
* available.
|
||||
* @param rb The user ring buffer.
|
||||
@@ -1518,8 +1114,7 @@ LIBBPF_API void *user_ring_buffer__reserve_blocking(struct user_ring_buffer *rb,
|
||||
__u32 size,
|
||||
int timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__submit()** submits a previously reserved sample
|
||||
/* @brief **user_ring_buffer__submit()** submits a previously reserved sample
|
||||
* into the ring buffer.
|
||||
* @param rb The user ring buffer.
|
||||
* @param sample A reserved sample.
|
||||
@@ -1529,8 +1124,7 @@ LIBBPF_API void *user_ring_buffer__reserve_blocking(struct user_ring_buffer *rb,
|
||||
*/
|
||||
LIBBPF_API void user_ring_buffer__submit(struct user_ring_buffer *rb, void *sample);
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__discard()** discards a previously reserved sample.
|
||||
/* @brief **user_ring_buffer__discard()** discards a previously reserved sample.
|
||||
* @param rb The user ring buffer.
|
||||
* @param sample A reserved sample.
|
||||
*
|
||||
@@ -1539,8 +1133,7 @@ LIBBPF_API void user_ring_buffer__submit(struct user_ring_buffer *rb, void *samp
|
||||
*/
|
||||
LIBBPF_API void user_ring_buffer__discard(struct user_ring_buffer *rb, void *sample);
|
||||
|
||||
/**
|
||||
* @brief **user_ring_buffer__free()** frees a ring buffer that was previously
|
||||
/* @brief **user_ring_buffer__free()** frees a ring buffer that was previously
|
||||
* created with **user_ring_buffer__new()**.
|
||||
* @param rb The user ring buffer being freed.
|
||||
*/
|
||||
@@ -1556,10 +1149,8 @@ typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
|
||||
/* common use perf buffer options */
|
||||
struct perf_buffer_opts {
|
||||
size_t sz;
|
||||
__u32 sample_period;
|
||||
size_t :0;
|
||||
};
|
||||
#define perf_buffer_opts__last_field sample_period
|
||||
#define perf_buffer_opts__last_field sz
|
||||
|
||||
/**
|
||||
* @brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
|
||||
@@ -1624,11 +1215,11 @@ LIBBPF_API int perf_buffer__buffer_fd(const struct perf_buffer *pb, size_t buf_i
|
||||
* memory region of the ring buffer.
|
||||
* This ring buffer can be used to implement a custom events consumer.
|
||||
* The ring buffer starts with the *struct perf_event_mmap_page*, which
|
||||
* holds the ring buffer management fields, when accessing the header
|
||||
* holds the ring buffer managment fields, when accessing the header
|
||||
* structure it's important to be SMP aware.
|
||||
* You can refer to *perf_event_read_simple* for a simple example.
|
||||
* @param pb the perf buffer structure
|
||||
* @param buf_idx the buffer index to retrieve
|
||||
* @param buf_idx the buffer index to retreive
|
||||
* @param buf (out) gets the base pointer of the mmap()'ed memory
|
||||
* @param buf_size (out) gets the size of the mmap()'ed region
|
||||
* @return 0 on success, negative error code for failure
|
||||
@@ -1720,7 +1311,6 @@ struct bpf_map_skeleton {
|
||||
const char *name;
|
||||
struct bpf_map **map;
|
||||
void **mmaped;
|
||||
struct bpf_link **link;
|
||||
};
|
||||
|
||||
struct bpf_prog_skeleton {
|
||||
@@ -1785,7 +1375,7 @@ LIBBPF_API void
|
||||
bpf_object__destroy_subskeleton(struct bpf_object_subskeleton *s);
|
||||
|
||||
struct gen_loader_opts {
|
||||
size_t sz; /* size of this struct, for forward/backward compatibility */
|
||||
size_t sz; /* size of this struct, for forward/backward compatiblity */
|
||||
const char *data;
|
||||
const char *insns;
|
||||
__u32 data_sz;
|
||||
@@ -1803,13 +1393,13 @@ enum libbpf_tristate {
|
||||
};
|
||||
|
||||
struct bpf_linker_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
};
|
||||
#define bpf_linker_opts__last_field sz
|
||||
|
||||
struct bpf_linker_file_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
};
|
||||
#define bpf_linker_file_opts__last_field sz
|
||||
@@ -1817,14 +1407,9 @@ struct bpf_linker_file_opts {
|
||||
struct bpf_linker;
|
||||
|
||||
LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts);
|
||||
LIBBPF_API struct bpf_linker *bpf_linker__new_fd(int fd, struct bpf_linker_opts *opts);
|
||||
LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,
|
||||
const char *filename,
|
||||
const struct bpf_linker_file_opts *opts);
|
||||
LIBBPF_API int bpf_linker__add_fd(struct bpf_linker *linker, int fd,
|
||||
const struct bpf_linker_file_opts *opts);
|
||||
LIBBPF_API int bpf_linker__add_buf(struct bpf_linker *linker, void *buf, size_t buf_sz,
|
||||
const struct bpf_linker_file_opts *opts);
|
||||
LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);
|
||||
LIBBPF_API void bpf_linker__free(struct bpf_linker *linker);
|
||||
|
||||
@@ -1857,7 +1442,7 @@ typedef int (*libbpf_prog_attach_fn_t)(const struct bpf_program *prog, long cook
|
||||
struct bpf_link **link);
|
||||
|
||||
struct libbpf_prog_handler_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
/* size of this struct, for forward/backward compatiblity */
|
||||
size_t sz;
|
||||
/* User-provided value that is passed to prog_setup_fn,
|
||||
* prog_prepare_load_fn, and prog_attach_fn callbacks. Allows user to
|
||||
|
||||
@@ -245,6 +245,7 @@ LIBBPF_0.3.0 {
|
||||
btf__parse_raw_split;
|
||||
btf__parse_split;
|
||||
btf__new_empty_split;
|
||||
btf__new_split;
|
||||
ring_buffer__epoll_fd;
|
||||
} LIBBPF_0.2.0;
|
||||
|
||||
@@ -325,6 +326,7 @@ LIBBPF_0.7.0 {
|
||||
bpf_xdp_detach;
|
||||
bpf_xdp_query;
|
||||
bpf_xdp_query_id;
|
||||
btf_ext__raw_data;
|
||||
libbpf_probe_bpf_helper;
|
||||
libbpf_probe_bpf_map_type;
|
||||
libbpf_probe_bpf_prog_type;
|
||||
@@ -365,14 +367,10 @@ LIBBPF_1.0.0 {
|
||||
libbpf_bpf_map_type_str;
|
||||
libbpf_bpf_prog_type_str;
|
||||
perf_buffer__buffer;
|
||||
} LIBBPF_0.8.0;
|
||||
};
|
||||
|
||||
LIBBPF_1.1.0 {
|
||||
global:
|
||||
bpf_btf_get_fd_by_id_opts;
|
||||
bpf_link_get_fd_by_id_opts;
|
||||
bpf_map_get_fd_by_id_opts;
|
||||
bpf_prog_get_fd_by_id_opts;
|
||||
user_ring_buffer__discard;
|
||||
user_ring_buffer__free;
|
||||
user_ring_buffer__new;
|
||||
@@ -380,67 +378,3 @@ LIBBPF_1.1.0 {
|
||||
user_ring_buffer__reserve_blocking;
|
||||
user_ring_buffer__submit;
|
||||
} LIBBPF_1.0.0;
|
||||
|
||||
LIBBPF_1.2.0 {
|
||||
global:
|
||||
bpf_btf_get_info_by_fd;
|
||||
bpf_link__update_map;
|
||||
bpf_link_get_info_by_fd;
|
||||
bpf_map_get_info_by_fd;
|
||||
bpf_prog_get_info_by_fd;
|
||||
} LIBBPF_1.1.0;
|
||||
|
||||
LIBBPF_1.3.0 {
|
||||
global:
|
||||
bpf_obj_pin_opts;
|
||||
bpf_object__unpin;
|
||||
bpf_prog_detach_opts;
|
||||
bpf_program__attach_netfilter;
|
||||
bpf_program__attach_netkit;
|
||||
bpf_program__attach_tcx;
|
||||
bpf_program__attach_uprobe_multi;
|
||||
ring__avail_data_size;
|
||||
ring__consume;
|
||||
ring__consumer_pos;
|
||||
ring__map_fd;
|
||||
ring__producer_pos;
|
||||
ring__size;
|
||||
ring_buffer__ring;
|
||||
} LIBBPF_1.2.0;
|
||||
|
||||
LIBBPF_1.4.0 {
|
||||
global:
|
||||
bpf_program__attach_raw_tracepoint_opts;
|
||||
bpf_raw_tracepoint_open_opts;
|
||||
bpf_token_create;
|
||||
btf__new_split;
|
||||
btf_ext__raw_data;
|
||||
} LIBBPF_1.3.0;
|
||||
|
||||
LIBBPF_1.5.0 {
|
||||
global:
|
||||
btf__distill_base;
|
||||
btf__relocate;
|
||||
btf_ext__endianness;
|
||||
btf_ext__set_endianness;
|
||||
bpf_map__autoattach;
|
||||
bpf_map__set_autoattach;
|
||||
bpf_object__token_fd;
|
||||
bpf_program__attach_sockmap;
|
||||
ring__consume_n;
|
||||
ring_buffer__consume_n;
|
||||
} LIBBPF_1.4.0;
|
||||
|
||||
LIBBPF_1.6.0 {
|
||||
global:
|
||||
bpf_linker__add_buf;
|
||||
bpf_linker__add_fd;
|
||||
bpf_linker__new_fd;
|
||||
bpf_object__prepare;
|
||||
bpf_program__func_info;
|
||||
bpf_program__func_info_cnt;
|
||||
bpf_program__line_info;
|
||||
bpf_program__line_info_cnt;
|
||||
btf__add_decl_attr;
|
||||
btf__add_type_attr;
|
||||
} LIBBPF_1.5.0;
|
||||
|
||||
@@ -70,23 +70,4 @@
|
||||
}; \
|
||||
})
|
||||
|
||||
/* Helper macro to clear and optionally reinitialize libbpf options struct
|
||||
*
|
||||
* Small helper macro to reset all fields and to reinitialize the common
|
||||
* structure size member. Values provided by users in struct initializer-
|
||||
* syntax as varargs can be provided as well to reinitialize options struct
|
||||
* specific members.
|
||||
*/
|
||||
#define LIBBPF_OPTS_RESET(NAME, ...) \
|
||||
do { \
|
||||
typeof(NAME) ___##NAME = ({ \
|
||||
memset(&___##NAME, 0, sizeof(NAME)); \
|
||||
(typeof(NAME)) { \
|
||||
.sz = sizeof(NAME), \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
}); \
|
||||
memcpy(&NAME, &___##NAME, sizeof(NAME)); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_COMMON_H */
|
||||
|
||||
@@ -39,14 +39,14 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
|
||||
|
||||
int libbpf_strerror(int err, char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!buf || !size)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
err = err > 0 ? err : -err;
|
||||
|
||||
if (err < __LIBBPF_ERRNO__START) {
|
||||
int ret;
|
||||
|
||||
ret = strerror_r(err, buf, size);
|
||||
buf[size - 1] = '\0';
|
||||
return libbpf_err_errno(ret);
|
||||
@@ -56,20 +56,12 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
||||
const char *msg;
|
||||
|
||||
msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
|
||||
ret = snprintf(buf, size, "%s", msg);
|
||||
snprintf(buf, size, "%s", msg);
|
||||
buf[size - 1] = '\0';
|
||||
/* The length of the buf and msg is positive.
|
||||
* A negative number may be returned only when the
|
||||
* size exceeds INT_MAX. Not likely to appear.
|
||||
*/
|
||||
if (ret >= size)
|
||||
return libbpf_err(-ERANGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = snprintf(buf, size, "Unknown libbpf error %d", err);
|
||||
snprintf(buf, size, "Unknown libbpf error %d", err);
|
||||
buf[size - 1] = '\0';
|
||||
if (ret >= size)
|
||||
return libbpf_err(-ERANGE);
|
||||
return libbpf_err(-ENOENT);
|
||||
}
|
||||
|
||||
@@ -10,30 +10,13 @@
|
||||
#define __LIBBPF_LIBBPF_INTERNAL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <byteswap.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <libelf.h>
|
||||
#include "relo_core.h"
|
||||
|
||||
/* Android's libc doesn't support AT_EACCESS in faccessat() implementation
|
||||
* ([0]), and just returns -EINVAL even if file exists and is accessible.
|
||||
* See [1] for issues caused by this.
|
||||
*
|
||||
* So just redefine it to 0 on Android.
|
||||
*
|
||||
* [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50
|
||||
* [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250
|
||||
*/
|
||||
#ifdef __ANDROID__
|
||||
#undef AT_EACCESS
|
||||
#define AT_EACCESS 0
|
||||
#endif
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
@@ -235,9 +218,6 @@ struct btf_type;
|
||||
struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id);
|
||||
const char *btf_kind_str(const struct btf_type *t);
|
||||
const struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id);
|
||||
const struct btf_header *btf_header(const struct btf *btf);
|
||||
void btf_set_base_btf(struct btf *btf, const struct btf *base_btf);
|
||||
int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map);
|
||||
|
||||
static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t)
|
||||
{
|
||||
@@ -374,42 +354,18 @@ enum kern_feature_id {
|
||||
FEAT_BTF_ENUM64,
|
||||
/* Kernel uses syscall wrapper (CONFIG_ARCH_HAS_SYSCALL_WRAPPER) */
|
||||
FEAT_SYSCALL_WRAPPER,
|
||||
/* BPF multi-uprobe link support */
|
||||
FEAT_UPROBE_MULTI_LINK,
|
||||
/* Kernel supports arg:ctx tag (__arg_ctx) for global subprogs natively */
|
||||
FEAT_ARG_CTX_TAG,
|
||||
/* Kernel supports '?' at the front of datasec names */
|
||||
FEAT_BTF_QMARK_DATASEC,
|
||||
__FEAT_CNT,
|
||||
};
|
||||
|
||||
enum kern_feature_result {
|
||||
FEAT_UNKNOWN = 0,
|
||||
FEAT_SUPPORTED = 1,
|
||||
FEAT_MISSING = 2,
|
||||
};
|
||||
|
||||
struct kern_feature_cache {
|
||||
enum kern_feature_result res[__FEAT_CNT];
|
||||
int token_fd;
|
||||
};
|
||||
|
||||
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
|
||||
int probe_memcg_account(void);
|
||||
bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
|
||||
|
||||
int probe_kern_syscall_wrapper(int token_fd);
|
||||
int probe_memcg_account(int token_fd);
|
||||
int bump_rlimit_memlock(void);
|
||||
|
||||
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
||||
int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len,
|
||||
int token_fd);
|
||||
int btf_load_into_kernel(struct btf *btf,
|
||||
char *log_buf, size_t log_sz, __u32 log_level,
|
||||
int token_fd);
|
||||
struct btf *btf_load_from_kernel(__u32 id, struct btf *base_btf, int token_fd);
|
||||
const char *str_sec, size_t str_len);
|
||||
int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level);
|
||||
|
||||
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
||||
void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
|
||||
@@ -450,11 +406,11 @@ struct btf_ext_info {
|
||||
*
|
||||
* The func_info subsection layout:
|
||||
* record size for struct bpf_func_info in the func_info subsection
|
||||
* struct btf_ext_info_sec for section #1
|
||||
* struct btf_sec_func_info for section #1
|
||||
* a list of bpf_func_info records for section #1
|
||||
* where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
|
||||
* but may not be identical
|
||||
* struct btf_ext_info_sec for section #2
|
||||
* struct btf_sec_func_info for section #2
|
||||
* a list of bpf_func_info records for section #2
|
||||
* ......
|
||||
*
|
||||
@@ -486,8 +442,6 @@ struct btf_ext {
|
||||
struct btf_ext_header *hdr;
|
||||
void *data;
|
||||
};
|
||||
void *data_swapped;
|
||||
bool swapped_endian;
|
||||
struct btf_ext_info func_info;
|
||||
struct btf_ext_info line_info;
|
||||
struct btf_ext_info core_relo_info;
|
||||
@@ -515,64 +469,21 @@ struct bpf_line_info_min {
|
||||
__u32 line_col;
|
||||
};
|
||||
|
||||
/* Functions to byte-swap info records */
|
||||
|
||||
typedef void (*info_rec_bswap_fn)(void *);
|
||||
|
||||
static inline void bpf_func_info_bswap(struct bpf_func_info *i)
|
||||
{
|
||||
i->insn_off = bswap_32(i->insn_off);
|
||||
i->type_id = bswap_32(i->type_id);
|
||||
}
|
||||
|
||||
static inline void bpf_line_info_bswap(struct bpf_line_info *i)
|
||||
{
|
||||
i->insn_off = bswap_32(i->insn_off);
|
||||
i->file_name_off = bswap_32(i->file_name_off);
|
||||
i->line_off = bswap_32(i->line_off);
|
||||
i->line_col = bswap_32(i->line_col);
|
||||
}
|
||||
|
||||
static inline void bpf_core_relo_bswap(struct bpf_core_relo *i)
|
||||
{
|
||||
i->insn_off = bswap_32(i->insn_off);
|
||||
i->type_id = bswap_32(i->type_id);
|
||||
i->access_str_off = bswap_32(i->access_str_off);
|
||||
i->kind = bswap_32(i->kind);
|
||||
}
|
||||
|
||||
enum btf_field_iter_kind {
|
||||
BTF_FIELD_ITER_IDS,
|
||||
BTF_FIELD_ITER_STRS,
|
||||
};
|
||||
|
||||
struct btf_field_desc {
|
||||
/* once-per-type offsets */
|
||||
int t_off_cnt, t_offs[2];
|
||||
/* member struct size, or zero, if no members */
|
||||
int m_sz;
|
||||
/* repeated per-member offsets */
|
||||
int m_off_cnt, m_offs[1];
|
||||
};
|
||||
|
||||
struct btf_field_iter {
|
||||
struct btf_field_desc desc;
|
||||
void *p;
|
||||
int m_idx;
|
||||
int off_idx;
|
||||
int vlen;
|
||||
};
|
||||
|
||||
int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, enum btf_field_iter_kind iter_kind);
|
||||
__u32 *btf_field_iter_next(struct btf_field_iter *it);
|
||||
|
||||
typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);
|
||||
typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);
|
||||
int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx);
|
||||
int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx);
|
||||
int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
|
||||
int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
|
||||
__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
|
||||
__u32 kind);
|
||||
|
||||
typedef int (*kallsyms_cb_t)(unsigned long long sym_addr, char sym_type,
|
||||
const char *sym_name, void *ctx);
|
||||
|
||||
int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *arg);
|
||||
|
||||
/* handle direct returned errors */
|
||||
static inline int libbpf_err(int ret)
|
||||
{
|
||||
@@ -618,27 +529,6 @@ static inline bool is_ldimm64_insn(struct bpf_insn *insn)
|
||||
return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
||||
}
|
||||
|
||||
static inline void bpf_insn_bswap(struct bpf_insn *insn)
|
||||
{
|
||||
__u8 tmp_reg = insn->dst_reg;
|
||||
|
||||
insn->dst_reg = insn->src_reg;
|
||||
insn->src_reg = tmp_reg;
|
||||
insn->off = bswap_16(insn->off);
|
||||
insn->imm = bswap_32(insn->imm);
|
||||
}
|
||||
|
||||
/* Unconditionally dup FD, ensuring it doesn't use [0, 2] range.
|
||||
* Original FD is not closed or altered in any other way.
|
||||
* Preserves original FD value, if it's invalid (negative).
|
||||
*/
|
||||
static inline int dup_good_fd(int fd)
|
||||
{
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
return fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
}
|
||||
|
||||
/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2
|
||||
* Takes ownership of the fd passed in, and closes it if calling
|
||||
* fcntl(fd, F_DUPFD_CLOEXEC, 3).
|
||||
@@ -650,10 +540,9 @@ static inline int ensure_good_fd(int fd)
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
if (fd < 3) {
|
||||
fd = dup_good_fd(fd);
|
||||
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
saved_errno = errno;
|
||||
close(old_fd);
|
||||
errno = saved_errno;
|
||||
if (fd < 0) {
|
||||
pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
||||
errno = saved_errno;
|
||||
@@ -662,34 +551,6 @@ static inline int ensure_good_fd(int fd)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline int sys_dup3(int oldfd, int newfd, int flags)
|
||||
{
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
}
|
||||
|
||||
/* Some versions of Android don't provide memfd_create() in their libc
|
||||
* implementation, so avoid complications and just go straight to Linux
|
||||
* syscall.
|
||||
*/
|
||||
static inline int sys_memfd_create(const char *name, unsigned flags)
|
||||
{
|
||||
return syscall(__NR_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
/* Point *fixed_fd* to the same file that *tmp_fd* points to.
|
||||
* Regardless of success, *tmp_fd* is closed.
|
||||
* Whatever *fixed_fd* pointed to is closed silently.
|
||||
*/
|
||||
static inline int reuse_fd(int fixed_fd, int tmp_fd)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = sys_dup3(tmp_fd, fixed_fd, O_CLOEXEC);
|
||||
err = err < 0 ? -errno : 0;
|
||||
close(tmp_fd); /* clean up temporary FD */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The following two functions are exposed to bpftool */
|
||||
int bpf_core_add_cands(struct bpf_core_cand *local_cand,
|
||||
size_t local_essent_len,
|
||||
@@ -715,25 +576,4 @@ static inline bool is_pow_of_2(size_t x)
|
||||
#define PROG_LOAD_ATTEMPTS 5
|
||||
int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts);
|
||||
|
||||
bool glob_match(const char *str, const char *pat);
|
||||
|
||||
long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name);
|
||||
long elf_find_func_offset_from_file(const char *binary_path, const char *name);
|
||||
|
||||
struct elf_fd {
|
||||
Elf *elf;
|
||||
int fd;
|
||||
};
|
||||
|
||||
int elf_open(const char *binary_path, struct elf_fd *elf_fd);
|
||||
void elf_close(struct elf_fd *elf_fd);
|
||||
|
||||
int elf_resolve_syms_offsets(const char *binary_path, int cnt,
|
||||
const char **syms, unsigned long **poffsets,
|
||||
int st_type);
|
||||
int elf_resolve_pattern_offsets(const char *binary_path, const char *pattern,
|
||||
unsigned long **poffsets, size_t *pcnt);
|
||||
|
||||
int probe_fd(int fd);
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||
|
||||
@@ -76,7 +76,7 @@ enum libbpf_strict_mode {
|
||||
* first BPF program or map creation operation. This is done only if
|
||||
* kernel is too old to support memcg-based memory accounting for BPF
|
||||
* subsystem. By default, RLIMIT_MEMLOCK limit is set to RLIM_INFINITY,
|
||||
* but it can be overridden with libbpf_set_memlock_rlim() API.
|
||||
* but it can be overriden with libbpf_set_memlock_rlim() API.
|
||||
* Note that libbpf_set_memlock_rlim() needs to be called before
|
||||
* the very first bpf_prog_load(), bpf_map_create() or bpf_object__load()
|
||||
* operation.
|
||||
@@ -97,7 +97,7 @@ LIBBPF_API int libbpf_set_strict_mode(enum libbpf_strict_mode mode);
|
||||
* @brief **libbpf_get_error()** extracts the error code from the passed
|
||||
* pointer
|
||||
* @param ptr pointer returned from libbpf API function
|
||||
* @return error code; or 0 if no error occurred
|
||||
* @return error code; or 0 if no error occured
|
||||
*
|
||||
* Note, as of libbpf 1.0 this function is not necessary and not recommended
|
||||
* to be used. Libbpf doesn't return error code embedded into the pointer
|
||||
|
||||
@@ -12,94 +12,11 @@
|
||||
#include <linux/btf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "bpf.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,
|
||||
* but Ubuntu provides /proc/version_signature file, as described at
|
||||
* https://ubuntu.com/kernel, with an example contents below, which we
|
||||
* can use to get a proper LINUX_VERSION_CODE.
|
||||
*
|
||||
* Ubuntu 5.4.0-12.15-generic 5.4.8
|
||||
*
|
||||
* In the above, 5.4.8 is what kernel is actually expecting, while
|
||||
* uname() call will return 5.4.0 in info.release.
|
||||
*/
|
||||
static __u32 get_ubuntu_kernel_version(void)
|
||||
{
|
||||
const char *ubuntu_kver_file = "/proc/version_signature";
|
||||
__u32 major, minor, patch;
|
||||
int ret;
|
||||
FILE *f;
|
||||
|
||||
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)
|
||||
return 0;
|
||||
|
||||
f = fopen(ubuntu_kver_file, "re");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
ret = fscanf(f, "%*s %*s %u.%u.%u\n", &major, &minor, &patch);
|
||||
fclose(f);
|
||||
if (ret != 3)
|
||||
return 0;
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
/* On Debian LINUX_VERSION_CODE doesn't correspond to info.release.
|
||||
* Instead, it is provided in info.version. An example content of
|
||||
* Debian 10 looks like the below.
|
||||
*
|
||||
* utsname::release 4.19.0-22-amd64
|
||||
* utsname::version #1 SMP Debian 4.19.260-1 (2022-09-29)
|
||||
*
|
||||
* In the above, 4.19.260 is what kernel is actually expecting, while
|
||||
* uname() call will return 4.19.0 in info.release.
|
||||
*/
|
||||
static __u32 get_debian_kernel_version(struct utsname *info)
|
||||
{
|
||||
__u32 major, minor, patch;
|
||||
char *p;
|
||||
|
||||
p = strstr(info->version, "Debian ");
|
||||
if (!p) {
|
||||
/* This is not a Debian kernel. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(p, "Debian %u.%u.%u", &major, &minor, &patch) != 3)
|
||||
return 0;
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
__u32 get_kernel_version(void)
|
||||
{
|
||||
__u32 major, minor, patch, version;
|
||||
struct utsname info;
|
||||
|
||||
/* Check if this is an Ubuntu kernel. */
|
||||
version = get_ubuntu_kernel_version();
|
||||
if (version != 0)
|
||||
return version;
|
||||
|
||||
uname(&info);
|
||||
|
||||
/* Check if this is a Debian kernel. */
|
||||
version = get_debian_kernel_version(&info);
|
||||
if (version != 0)
|
||||
return version;
|
||||
|
||||
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
|
||||
return 0;
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||
const struct bpf_insn *insns, size_t insns_cnt,
|
||||
char *log_buf, size_t log_buf_sz)
|
||||
@@ -181,9 +98,6 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||
break;
|
||||
case BPF_PROG_TYPE_NETFILTER:
|
||||
opts.expected_attach_type = BPF_NETFILTER;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -219,8 +133,7 @@ int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts)
|
||||
}
|
||||
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len,
|
||||
int token_fd)
|
||||
const char *str_sec, size_t str_len)
|
||||
{
|
||||
struct btf_header hdr = {
|
||||
.magic = BTF_MAGIC,
|
||||
@@ -230,10 +143,6 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
.str_off = types_len,
|
||||
.str_len = str_len,
|
||||
};
|
||||
LIBBPF_OPTS(bpf_btf_load_opts, opts,
|
||||
.token_fd = token_fd,
|
||||
.btf_flags = token_fd ? BPF_F_TOKEN_FD : 0,
|
||||
);
|
||||
int btf_fd, btf_len;
|
||||
__u8 *raw_btf;
|
||||
|
||||
@@ -246,7 +155,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
|
||||
memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
|
||||
|
||||
btf_fd = bpf_btf_load(raw_btf, btf_len, &opts);
|
||||
btf_fd = bpf_btf_load(raw_btf, btf_len, NULL);
|
||||
|
||||
free(raw_btf);
|
||||
return btf_fd;
|
||||
@@ -276,7 +185,7 @@ static int load_local_storage_btf(void)
|
||||
};
|
||||
|
||||
return libbpf__load_raw_btf((char *)types, sizeof(types),
|
||||
strs, sizeof(strs), 0);
|
||||
strs, sizeof(strs));
|
||||
}
|
||||
|
||||
static int probe_map_create(enum bpf_map_type map_type)
|
||||
@@ -312,7 +221,6 @@ static int probe_map_create(enum bpf_map_type map_type)
|
||||
case BPF_MAP_TYPE_SK_STORAGE:
|
||||
case BPF_MAP_TYPE_INODE_STORAGE:
|
||||
case BPF_MAP_TYPE_TASK_STORAGE:
|
||||
case BPF_MAP_TYPE_CGRP_STORAGE:
|
||||
btf_key_type_id = 1;
|
||||
btf_value_type_id = 3;
|
||||
value_size = 8;
|
||||
@@ -326,25 +234,17 @@ static int probe_map_create(enum bpf_map_type map_type)
|
||||
case BPF_MAP_TYPE_USER_RINGBUF:
|
||||
key_size = 0;
|
||||
value_size = 0;
|
||||
max_entries = sysconf(_SC_PAGE_SIZE);
|
||||
max_entries = 4096;
|
||||
break;
|
||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
||||
opts.btf_vmlinux_value_type_id = 1;
|
||||
opts.value_type_btf_obj_fd = -1;
|
||||
exp_err = -524; /* -ENOTSUPP */
|
||||
break;
|
||||
case BPF_MAP_TYPE_BLOOM_FILTER:
|
||||
key_size = 0;
|
||||
max_entries = 1;
|
||||
break;
|
||||
case BPF_MAP_TYPE_ARENA:
|
||||
key_size = 0;
|
||||
value_size = 0;
|
||||
max_entries = 1; /* one page */
|
||||
opts.map_extra = 0; /* can mmap() at any address */
|
||||
opts.map_flags = BPF_F_MMAPABLE;
|
||||
break;
|
||||
case BPF_MAP_TYPE_HASH:
|
||||
case BPF_MAP_TYPE_ARRAY:
|
||||
case BPF_MAP_TYPE_PROG_ARRAY:
|
||||
@@ -448,8 +348,7 @@ int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helpe
|
||||
/* If BPF verifier doesn't recognize BPF helper ID (enum bpf_func_id)
|
||||
* at all, it will emit something like "invalid func unknown#181".
|
||||
* If BPF verifier recognizes BPF helper but it's not supported for
|
||||
* given BPF program type, it will emit "unknown func bpf_sys_bpf#166"
|
||||
* or "program of this type cannot use helper bpf_sys_bpf#166".
|
||||
* given BPF program type, it will emit "unknown func bpf_sys_bpf#166".
|
||||
* In both cases, provided combination of BPF program type and BPF
|
||||
* helper is not supported by the kernel.
|
||||
* In all other cases, probe_prog_load() above will either succeed (e.g.,
|
||||
@@ -458,8 +357,7 @@ int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helpe
|
||||
* that), or we'll get some more specific BPF verifier error about
|
||||
* some unsatisfied conditions.
|
||||
*/
|
||||
if (ret == 0 && (strstr(buf, "invalid func ") || strstr(buf, "unknown func ") ||
|
||||
strstr(buf, "program of this type cannot use helper ")))
|
||||
if (ret == 0 && (strstr(buf, "invalid func ") || strstr(buf, "unknown func ")))
|
||||
return 0;
|
||||
return 1; /* assume supported */
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
#define __LIBBPF_VERSION_H
|
||||
|
||||
#define LIBBPF_MAJOR_VERSION 1
|
||||
#define LIBBPF_MINOR_VERSION 6
|
||||
#define LIBBPF_MINOR_VERSION 1
|
||||
|
||||
#endif /* __LIBBPF_VERSION_H */
|
||||
|
||||
476
src/linker.c
476
src/linker.c
@@ -4,10 +4,6 @@
|
||||
*
|
||||
* Copyright (c) 2021 Facebook
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -20,12 +16,10 @@
|
||||
#include <elf.h>
|
||||
#include <libelf.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "libbpf.h"
|
||||
#include "btf.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "strset.h"
|
||||
#include "str_error.h"
|
||||
|
||||
#define BTF_EXTERN_SEC ".extern"
|
||||
|
||||
@@ -141,7 +135,6 @@ struct bpf_linker {
|
||||
int fd;
|
||||
Elf *elf;
|
||||
Elf64_Ehdr *elf_hdr;
|
||||
bool swapped_endian;
|
||||
|
||||
/* Output sections metadata */
|
||||
struct dst_sec *secs;
|
||||
@@ -157,19 +150,15 @@ struct bpf_linker {
|
||||
/* global (including extern) ELF symbols */
|
||||
int glob_sym_cnt;
|
||||
struct glob_sym *glob_syms;
|
||||
|
||||
bool fd_is_owned;
|
||||
};
|
||||
|
||||
#define pr_warn_elf(fmt, ...) \
|
||||
libbpf_print(LIBBPF_WARN, "libbpf: " fmt ": %s\n", ##__VA_ARGS__, elf_errmsg(-1))
|
||||
|
||||
static int init_output_elf(struct bpf_linker *linker);
|
||||
static int init_output_elf(struct bpf_linker *linker, const char *file);
|
||||
|
||||
static int bpf_linker_add_file(struct bpf_linker *linker, int fd,
|
||||
const char *filename);
|
||||
|
||||
static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
||||
const struct bpf_linker_file_opts *opts,
|
||||
struct src_obj *obj);
|
||||
static int linker_sanity_check_elf(struct src_obj *obj);
|
||||
static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec);
|
||||
@@ -200,7 +189,7 @@ void bpf_linker__free(struct bpf_linker *linker)
|
||||
if (linker->elf)
|
||||
elf_end(linker->elf);
|
||||
|
||||
if (linker->fd >= 0 && linker->fd_is_owned)
|
||||
if (linker->fd >= 0)
|
||||
close(linker->fd);
|
||||
|
||||
strset__free(linker->strtab_strs);
|
||||
@@ -242,63 +231,9 @@ struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts
|
||||
if (!linker)
|
||||
return errno = ENOMEM, NULL;
|
||||
|
||||
linker->filename = strdup(filename);
|
||||
if (!linker->filename) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
linker->fd = -1;
|
||||
|
||||
linker->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
|
||||
if (linker->fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to create '%s': %d\n", filename, err);
|
||||
goto err_out;
|
||||
}
|
||||
linker->fd_is_owned = true;
|
||||
|
||||
err = init_output_elf(linker);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return linker;
|
||||
|
||||
err_out:
|
||||
bpf_linker__free(linker);
|
||||
return errno = -err, NULL;
|
||||
}
|
||||
|
||||
struct bpf_linker *bpf_linker__new_fd(int fd, struct bpf_linker_opts *opts)
|
||||
{
|
||||
struct bpf_linker *linker;
|
||||
char filename[32];
|
||||
int err;
|
||||
|
||||
if (fd < 0)
|
||||
return errno = EINVAL, NULL;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_linker_opts))
|
||||
return errno = EINVAL, NULL;
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||
pr_warn_elf("libelf initialization failed");
|
||||
return errno = EINVAL, NULL;
|
||||
}
|
||||
|
||||
linker = calloc(1, sizeof(*linker));
|
||||
if (!linker)
|
||||
return errno = ENOMEM, NULL;
|
||||
|
||||
snprintf(filename, sizeof(filename), "fd:%d", fd);
|
||||
linker->filename = strdup(filename);
|
||||
if (!linker->filename) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
linker->fd = fd;
|
||||
linker->fd_is_owned = false;
|
||||
|
||||
err = init_output_elf(linker);
|
||||
err = init_output_elf(linker, filename);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@@ -357,12 +292,23 @@ static Elf64_Sym *add_new_sym(struct bpf_linker *linker, size_t *sym_idx)
|
||||
return sym;
|
||||
}
|
||||
|
||||
static int init_output_elf(struct bpf_linker *linker)
|
||||
static int init_output_elf(struct bpf_linker *linker, const char *file)
|
||||
{
|
||||
int err, str_off;
|
||||
Elf64_Sym *init_sym;
|
||||
struct dst_sec *sec;
|
||||
|
||||
linker->filename = strdup(file);
|
||||
if (!linker->filename)
|
||||
return -ENOMEM;
|
||||
|
||||
linker->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
|
||||
if (linker->fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to create '%s': %d\n", file, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
linker->elf = elf_begin(linker->fd, ELF_C_WRITE, NULL);
|
||||
if (!linker->elf) {
|
||||
pr_warn_elf("failed to create ELF object");
|
||||
@@ -378,8 +324,13 @@ static int init_output_elf(struct bpf_linker *linker)
|
||||
|
||||
linker->elf_hdr->e_machine = EM_BPF;
|
||||
linker->elf_hdr->e_type = ET_REL;
|
||||
/* Set unknown ELF endianness, assign later from input files */
|
||||
linker->elf_hdr->e_ident[EI_DATA] = ELFDATANONE;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
||||
#else
|
||||
#error "Unknown __BYTE_ORDER__"
|
||||
#endif
|
||||
|
||||
/* STRTAB */
|
||||
/* initialize strset with an empty string to conform to ELF */
|
||||
@@ -445,8 +396,6 @@ static int init_output_elf(struct bpf_linker *linker)
|
||||
pr_warn_elf("failed to create SYMTAB data");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Ensure libelf translates byte-order of symbol records */
|
||||
sec->data->d_type = ELF_T_SYM;
|
||||
|
||||
str_off = strset__add_str(linker->strtab_strs, sec->sec_name);
|
||||
if (str_off < 0)
|
||||
@@ -488,16 +437,19 @@ static int init_output_elf(struct bpf_linker *linker)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_linker_add_file(struct bpf_linker *linker, int fd,
|
||||
const char *filename)
|
||||
int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
|
||||
const struct bpf_linker_file_opts *opts)
|
||||
{
|
||||
struct src_obj obj = {};
|
||||
int err = 0;
|
||||
|
||||
obj.filename = filename;
|
||||
obj.fd = fd;
|
||||
if (!OPTS_VALID(opts, bpf_linker_file_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
err = err ?: linker_load_obj_file(linker, &obj);
|
||||
if (!linker->elf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
err = err ?: linker_load_obj_file(linker, filename, opts, &obj);
|
||||
err = err ?: linker_append_sec_data(linker, &obj);
|
||||
err = err ?: linker_append_elf_syms(linker, &obj);
|
||||
err = err ?: linker_append_elf_relos(linker, &obj);
|
||||
@@ -512,91 +464,12 @@ static int bpf_linker_add_file(struct bpf_linker *linker, int fd,
|
||||
free(obj.sym_map);
|
||||
if (obj.elf)
|
||||
elf_end(obj.elf);
|
||||
if (obj.fd >= 0)
|
||||
close(obj.fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
|
||||
const struct bpf_linker_file_opts *opts)
|
||||
{
|
||||
int fd, err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_linker_file_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (!linker->elf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
fd = open(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to open file '%s': %s\n", filename, errstr(err));
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
err = bpf_linker_add_file(linker, fd, filename);
|
||||
close(fd);
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
int bpf_linker__add_fd(struct bpf_linker *linker, int fd,
|
||||
const struct bpf_linker_file_opts *opts)
|
||||
{
|
||||
char filename[32];
|
||||
int err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_linker_file_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (!linker->elf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (fd < 0)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
snprintf(filename, sizeof(filename), "fd:%d", fd);
|
||||
err = bpf_linker_add_file(linker, fd, filename);
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
int bpf_linker__add_buf(struct bpf_linker *linker, void *buf, size_t buf_sz,
|
||||
const struct bpf_linker_file_opts *opts)
|
||||
{
|
||||
char filename[32];
|
||||
int fd, written, ret;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_linker_file_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (!linker->elf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
snprintf(filename, sizeof(filename), "mem:%p+%zu", buf, buf_sz);
|
||||
|
||||
fd = sys_memfd_create(filename, 0);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("failed to create memfd '%s': %s\n", filename, errstr(ret));
|
||||
return libbpf_err(ret);
|
||||
}
|
||||
|
||||
written = 0;
|
||||
while (written < buf_sz) {
|
||||
ret = write(fd, buf, buf_sz);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
pr_warn("failed to write '%s': %s\n", filename, errstr(ret));
|
||||
goto err_out;
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
|
||||
ret = bpf_linker_add_file(linker, fd, filename);
|
||||
err_out:
|
||||
close(fd);
|
||||
return libbpf_err(ret);
|
||||
}
|
||||
|
||||
static bool is_dwarf_sec_name(const char *name)
|
||||
{
|
||||
/* approximation, but the actual list is too long */
|
||||
@@ -662,69 +535,65 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name)
|
||||
return sec;
|
||||
}
|
||||
|
||||
static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
||||
const struct bpf_linker_file_opts *opts,
|
||||
struct src_obj *obj)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
const int host_endianness = ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
const int host_endianness = ELFDATA2MSB;
|
||||
#else
|
||||
#error "Unknown __BYTE_ORDER__"
|
||||
#endif
|
||||
int err = 0;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *data;
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Shdr *shdr;
|
||||
struct src_sec *sec;
|
||||
unsigned char obj_byteorder;
|
||||
unsigned char link_byteorder = linker->elf_hdr->e_ident[EI_DATA];
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
const unsigned char host_byteorder = ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
const unsigned char host_byteorder = ELFDATA2MSB;
|
||||
#else
|
||||
#error "Unknown __BYTE_ORDER__"
|
||||
#endif
|
||||
|
||||
pr_debug("linker: adding object file '%s'...\n", obj->filename);
|
||||
pr_debug("linker: adding object file '%s'...\n", filename);
|
||||
|
||||
obj->filename = filename;
|
||||
|
||||
obj->fd = open(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (obj->fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to open file '%s': %d\n", filename, err);
|
||||
return err;
|
||||
}
|
||||
obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!obj->elf) {
|
||||
pr_warn_elf("failed to parse ELF file '%s'", obj->filename);
|
||||
return -EINVAL;
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to parse ELF file '%s'", filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Sanity check ELF file high-level properties */
|
||||
ehdr = elf64_getehdr(obj->elf);
|
||||
if (!ehdr) {
|
||||
pr_warn_elf("failed to get ELF header for %s", obj->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Linker output endianness set by first input object */
|
||||
obj_byteorder = ehdr->e_ident[EI_DATA];
|
||||
if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) {
|
||||
err = -EOPNOTSUPP;
|
||||
pr_warn("unknown byte order of ELF file %s\n", obj->filename);
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to get ELF header for %s", filename);
|
||||
return err;
|
||||
}
|
||||
if (link_byteorder == ELFDATANONE) {
|
||||
linker->elf_hdr->e_ident[EI_DATA] = obj_byteorder;
|
||||
linker->swapped_endian = obj_byteorder != host_byteorder;
|
||||
pr_debug("linker: set %s-endian output byte order\n",
|
||||
obj_byteorder == ELFDATA2MSB ? "big" : "little");
|
||||
} else if (link_byteorder != obj_byteorder) {
|
||||
if (ehdr->e_ident[EI_DATA] != host_endianness) {
|
||||
err = -EOPNOTSUPP;
|
||||
pr_warn("byte order mismatch with ELF file %s\n", obj->filename);
|
||||
pr_warn_elf("unsupported byte order of ELF file %s", filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ehdr->e_type != ET_REL
|
||||
|| ehdr->e_machine != EM_BPF
|
||||
|| ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
|
||||
err = -EOPNOTSUPP;
|
||||
pr_warn_elf("unsupported kind of ELF file %s", obj->filename);
|
||||
pr_warn_elf("unsupported kind of ELF file %s", filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) {
|
||||
pr_warn_elf("failed to get SHSTRTAB section index for %s", obj->filename);
|
||||
return -EINVAL;
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to get SHSTRTAB section index for %s", filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
scn = NULL;
|
||||
@@ -734,23 +603,26 @@ static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
|
||||
shdr = elf64_getshdr(scn);
|
||||
if (!shdr) {
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to get section #%zu header for %s",
|
||||
sec_idx, obj->filename);
|
||||
return -EINVAL;
|
||||
sec_idx, filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name);
|
||||
if (!sec_name) {
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to get section #%zu name for %s",
|
||||
sec_idx, obj->filename);
|
||||
return -EINVAL;
|
||||
sec_idx, filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = elf_getdata(scn, 0);
|
||||
if (!data) {
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to get section #%zu (%s) data from %s",
|
||||
sec_idx, sec_name, obj->filename);
|
||||
return -EINVAL;
|
||||
sec_idx, sec_name, filename);
|
||||
return err;
|
||||
}
|
||||
|
||||
sec = add_src_sec(obj, sec_name);
|
||||
@@ -784,8 +656,7 @@ static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
obj->btf = btf__new(data->d_buf, shdr->sh_size);
|
||||
err = libbpf_get_error(obj->btf);
|
||||
if (err) {
|
||||
pr_warn("failed to parse .BTF from %s: %s\n",
|
||||
obj->filename, errstr(err));
|
||||
pr_warn("failed to parse .BTF from %s: %d\n", filename, err);
|
||||
return err;
|
||||
}
|
||||
sec->skipped = true;
|
||||
@@ -795,8 +666,7 @@ static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
obj->btf_ext = btf_ext__new(data->d_buf, shdr->sh_size);
|
||||
err = libbpf_get_error(obj->btf_ext);
|
||||
if (err) {
|
||||
pr_warn("failed to parse .BTF.ext from '%s': %s\n",
|
||||
obj->filename, errstr(err));
|
||||
pr_warn("failed to parse .BTF.ext from '%s': %d\n", filename, err);
|
||||
return err;
|
||||
}
|
||||
sec->skipped = true;
|
||||
@@ -813,7 +683,7 @@ static int linker_load_obj_file(struct bpf_linker *linker,
|
||||
break;
|
||||
default:
|
||||
pr_warn("unrecognized section #%zu (%s) in %s\n",
|
||||
sec_idx, sec_name, obj->filename);
|
||||
sec_idx, sec_name, filename);
|
||||
err = -EINVAL;
|
||||
return err;
|
||||
}
|
||||
@@ -849,28 +719,13 @@ static int linker_sanity_check_elf(struct src_obj *obj)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_dwarf_sec_name(sec->sec_name))
|
||||
continue;
|
||||
if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign))
|
||||
return -EINVAL;
|
||||
if (sec->shdr->sh_addralign != sec->data->d_align)
|
||||
return -EINVAL;
|
||||
|
||||
if (sec->shdr->sh_addralign && !is_pow_of_2(sec->shdr->sh_addralign)) {
|
||||
pr_warn("ELF section #%zu alignment %llu is non pow-of-2 alignment in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign,
|
||||
obj->filename);
|
||||
if (sec->shdr->sh_size != sec->data->d_size)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (sec->shdr->sh_addralign != sec->data->d_align) {
|
||||
pr_warn("ELF section #%zu has inconsistent alignment addr=%llu != d=%llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_addralign,
|
||||
(long long unsigned)sec->data->d_align, obj->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sec->shdr->sh_size != sec->data->d_size) {
|
||||
pr_warn("ELF section #%zu has inconsistent section size sh=%llu != d=%llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_size,
|
||||
(long long unsigned)sec->data->d_size, obj->filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (sec->shdr->sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
@@ -882,12 +737,8 @@ static int linker_sanity_check_elf(struct src_obj *obj)
|
||||
break;
|
||||
case SHT_PROGBITS:
|
||||
if (sec->shdr->sh_flags & SHF_EXECINSTR) {
|
||||
if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0) {
|
||||
pr_warn("ELF section #%zu has unexpected size alignment %llu in %s\n",
|
||||
sec->sec_idx, (long long unsigned)sec->shdr->sh_size,
|
||||
obj->filename);
|
||||
if (sec->shdr->sh_size % sizeof(struct bpf_insn) != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHT_NOBITS:
|
||||
@@ -1087,33 +938,19 @@ static int check_btf_str_off(__u32 *str_off, void *ctx)
|
||||
static int linker_sanity_check_btf(struct src_obj *obj)
|
||||
{
|
||||
struct btf_type *t;
|
||||
int i, n, err;
|
||||
int i, n, err = 0;
|
||||
|
||||
if (!obj->btf)
|
||||
return 0;
|
||||
|
||||
n = btf__type_cnt(obj->btf);
|
||||
for (i = 1; i < n; i++) {
|
||||
struct btf_field_iter it;
|
||||
__u32 *type_id, *str_off;
|
||||
|
||||
t = btf_type_by_id(obj->btf, i);
|
||||
|
||||
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS);
|
||||
err = err ?: btf_type_visit_type_ids(t, check_btf_type_id, obj->btf);
|
||||
err = err ?: btf_type_visit_str_offs(t, check_btf_str_off, obj->btf);
|
||||
if (err)
|
||||
return err;
|
||||
while ((type_id = btf_field_iter_next(&it))) {
|
||||
if (*type_id >= n)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS);
|
||||
if (err)
|
||||
return err;
|
||||
while ((str_off = btf_field_iter_next(&it))) {
|
||||
if (!btf__str_by_offset(obj->btf, *str_off))
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1239,24 +1076,6 @@ static bool sec_content_is_same(struct dst_sec *dst_sec, struct src_sec *src_sec
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_exec_sec(struct dst_sec *sec)
|
||||
{
|
||||
if (!sec || sec->ephemeral)
|
||||
return false;
|
||||
return (sec->shdr->sh_type == SHT_PROGBITS) &&
|
||||
(sec->shdr->sh_flags & SHF_EXECINSTR);
|
||||
}
|
||||
|
||||
static void exec_sec_bswap(void *raw_data, int size)
|
||||
{
|
||||
const int insn_cnt = size / sizeof(struct bpf_insn);
|
||||
struct bpf_insn *insn = raw_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++)
|
||||
bpf_insn_bswap(insn);
|
||||
}
|
||||
|
||||
static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src_sec *src)
|
||||
{
|
||||
void *tmp;
|
||||
@@ -1296,19 +1115,7 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src
|
||||
|
||||
if (src->shdr->sh_type != SHT_NOBITS) {
|
||||
tmp = realloc(dst->raw_data, dst_final_sz);
|
||||
/* If dst_align_sz == 0, realloc() behaves in a special way:
|
||||
* 1. When dst->raw_data is NULL it returns:
|
||||
* "either NULL or a pointer suitable to be passed to free()" [1].
|
||||
* 2. When dst->raw_data is not-NULL it frees dst->raw_data and returns NULL,
|
||||
* thus invalidating any "pointer suitable to be passed to free()" obtained
|
||||
* at step (1).
|
||||
*
|
||||
* The dst_align_sz > 0 check avoids error exit after (2), otherwise
|
||||
* dst->raw_data would be freed again in bpf_linker__free().
|
||||
*
|
||||
* [1] man 3 realloc
|
||||
*/
|
||||
if (!tmp && dst_align_sz > 0)
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
dst->raw_data = tmp;
|
||||
|
||||
@@ -1316,10 +1123,6 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src
|
||||
memset(dst->raw_data + dst->sec_sz, 0, dst_align_sz - dst->sec_sz);
|
||||
/* now copy src data at a properly aligned offset */
|
||||
memcpy(dst->raw_data + dst_align_sz, src->data->d_buf, src->shdr->sh_size);
|
||||
|
||||
/* convert added bpf insns to native byte-order */
|
||||
if (linker->swapped_endian && is_exec_sec(dst))
|
||||
exec_sec_bswap(dst->raw_data + dst_align_sz, src->shdr->sh_size);
|
||||
}
|
||||
|
||||
dst->sec_sz = dst_final_sz;
|
||||
@@ -1376,7 +1179,7 @@ static int linker_append_sec_data(struct bpf_linker *linker, struct src_obj *obj
|
||||
} else {
|
||||
if (!secs_match(dst_sec, src_sec)) {
|
||||
pr_warn("ELF sections %s are incompatible\n", src_sec->sec_name);
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* "license" and "version" sections are deduped */
|
||||
@@ -1565,7 +1368,7 @@ recur:
|
||||
return true;
|
||||
case BTF_KIND_PTR:
|
||||
/* just validate overall shape of the referenced type, so no
|
||||
* contents comparison for struct/union, and allowed fwd vs
|
||||
* contents comparison for struct/union, and allowd fwd vs
|
||||
* struct/union
|
||||
*/
|
||||
exact = false;
|
||||
@@ -2114,7 +1917,7 @@ static int linker_append_elf_sym(struct bpf_linker *linker, struct src_obj *obj,
|
||||
|
||||
/* If existing symbol is a strong resolved symbol, bail out,
|
||||
* because we lost resolution battle have nothing to
|
||||
* contribute. We already checked above that there is no
|
||||
* contribute. We already checked abover that there is no
|
||||
* strong-strong conflict. We also already tightened binding
|
||||
* and visibility, so nothing else to contribute at that point.
|
||||
*/
|
||||
@@ -2163,7 +1966,7 @@ add_sym:
|
||||
|
||||
obj->sym_map[src_sym_idx] = dst_sym_idx;
|
||||
|
||||
if (sym_type == STT_SECTION && dst_sec) {
|
||||
if (sym_type == STT_SECTION && dst_sym) {
|
||||
dst_sec->sec_sym_idx = dst_sym_idx;
|
||||
dst_sym->st_value = 0;
|
||||
}
|
||||
@@ -2194,6 +1997,7 @@ add_sym:
|
||||
static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *obj)
|
||||
{
|
||||
struct src_sec *src_symtab = &obj->secs[obj->symtab_sec_idx];
|
||||
struct dst_sec *dst_symtab;
|
||||
int i, err;
|
||||
|
||||
for (i = 1; i < obj->sec_cnt; i++) {
|
||||
@@ -2223,9 +2027,12 @@ static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *ob
|
||||
}
|
||||
} else if (!secs_match(dst_sec, src_sec)) {
|
||||
pr_warn("sections %s are not compatible\n", src_sec->sec_name);
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add_dst_sec() above could have invalidated linker->secs */
|
||||
dst_symtab = &linker->secs[linker->symtab_sec_idx];
|
||||
|
||||
/* shdr->sh_link points to SYMTAB */
|
||||
dst_sec->shdr->sh_link = linker->symtab_sec_idx;
|
||||
|
||||
@@ -2242,13 +2049,16 @@ static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *ob
|
||||
dst_rel = dst_sec->raw_data + src_sec->dst_off;
|
||||
n = src_sec->shdr->sh_size / src_sec->shdr->sh_entsize;
|
||||
for (j = 0; j < n; j++, src_rel++, dst_rel++) {
|
||||
size_t src_sym_idx, dst_sym_idx, sym_type;
|
||||
Elf64_Sym *src_sym;
|
||||
size_t src_sym_idx = ELF64_R_SYM(src_rel->r_info);
|
||||
size_t sym_type = ELF64_R_TYPE(src_rel->r_info);
|
||||
Elf64_Sym *src_sym, *dst_sym;
|
||||
size_t dst_sym_idx;
|
||||
|
||||
src_sym_idx = ELF64_R_SYM(src_rel->r_info);
|
||||
src_sym = src_symtab->data->d_buf + sizeof(*src_sym) * src_sym_idx;
|
||||
|
||||
dst_sym_idx = obj->sym_map[src_sym_idx];
|
||||
dst_sym = dst_symtab->raw_data + sizeof(*dst_sym) * dst_sym_idx;
|
||||
dst_rel->r_offset += src_linked_sec->dst_off;
|
||||
sym_type = ELF64_R_TYPE(src_rel->r_info);
|
||||
dst_rel->r_info = ELF64_R_INFO(dst_sym_idx, sym_type);
|
||||
@@ -2379,17 +2189,10 @@ static int linker_fixup_btf(struct src_obj *obj)
|
||||
vi = btf_var_secinfos(t);
|
||||
for (j = 0, m = btf_vlen(t); j < m; j++, vi++) {
|
||||
const struct btf_type *vt = btf__type_by_id(obj->btf, vi->type);
|
||||
const char *var_name;
|
||||
int var_linkage;
|
||||
const char *var_name = btf__str_by_offset(obj->btf, vt->name_off);
|
||||
int var_linkage = btf_var(vt)->linkage;
|
||||
Elf64_Sym *sym;
|
||||
|
||||
/* could be a variable or function */
|
||||
if (!btf_is_var(vt))
|
||||
continue;
|
||||
|
||||
var_name = btf__str_by_offset(obj->btf, vt->name_off);
|
||||
var_linkage = btf_var(vt)->linkage;
|
||||
|
||||
/* no need to patch up static or extern vars */
|
||||
if (var_linkage != BTF_VAR_GLOBAL_ALLOCATED)
|
||||
continue;
|
||||
@@ -2407,10 +2210,26 @@ static int linker_fixup_btf(struct src_obj *obj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remap_type_id(__u32 *type_id, void *ctx)
|
||||
{
|
||||
int *id_map = ctx;
|
||||
int new_id = id_map[*type_id];
|
||||
|
||||
/* Error out if the type wasn't remapped. Ignore VOID which stays VOID. */
|
||||
if (new_id == 0 && *type_id != 0) {
|
||||
pr_warn("failed to find new ID mapping for original BTF type ID %u\n", *type_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*type_id = id_map[*type_id];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
int i, j, n, start_id, id, err;
|
||||
int i, j, n, start_id, id;
|
||||
const char *name;
|
||||
|
||||
if (!obj->btf)
|
||||
@@ -2481,25 +2300,9 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
|
||||
n = btf__type_cnt(linker->btf);
|
||||
for (i = start_id; i < n; i++) {
|
||||
struct btf_type *dst_t = btf_type_by_id(linker->btf, i);
|
||||
struct btf_field_iter it;
|
||||
__u32 *type_id;
|
||||
|
||||
err = btf_field_iter_init(&it, dst_t, BTF_FIELD_ITER_IDS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while ((type_id = btf_field_iter_next(&it))) {
|
||||
int new_id = obj->btf_type_map[*type_id];
|
||||
|
||||
/* Error out if the type wasn't remapped. Ignore VOID which stays VOID. */
|
||||
if (new_id == 0 && *type_id != 0) {
|
||||
pr_warn("failed to find new ID mapping for original BTF type ID %u\n",
|
||||
*type_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*type_id = obj->btf_type_map[*type_id];
|
||||
}
|
||||
if (btf_type_visit_type_ids(dst_t, remap_type_id, obj->btf_type_map))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Rewrite VAR/FUNC underlying types (i.e., FUNC's FUNC_PROTO and VAR's
|
||||
@@ -2567,10 +2370,6 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
|
||||
if (glob_sym && glob_sym->var_idx >= 0) {
|
||||
__s64 sz;
|
||||
|
||||
/* FUNCs don't have size, nothing to update */
|
||||
if (btf_is_func(t))
|
||||
continue;
|
||||
|
||||
dst_var = &dst_sec->sec_vars[glob_sym->var_idx];
|
||||
/* Because underlying BTF type might have
|
||||
* changed, so might its size have changed, so
|
||||
@@ -2784,32 +2583,27 @@ int bpf_linker__finalize(struct bpf_linker *linker)
|
||||
if (!sec->scn)
|
||||
continue;
|
||||
|
||||
/* restore sections with bpf insns to target byte-order */
|
||||
if (linker->swapped_endian && is_exec_sec(sec))
|
||||
exec_sec_bswap(sec->raw_data, sec->sec_sz);
|
||||
|
||||
sec->data->d_buf = sec->raw_data;
|
||||
}
|
||||
|
||||
/* Finalize ELF layout */
|
||||
if (elf_update(linker->elf, ELF_C_NULL) < 0) {
|
||||
err = -EINVAL;
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to finalize ELF layout");
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
/* Write out final ELF contents */
|
||||
if (elf_update(linker->elf, ELF_C_WRITE) < 0) {
|
||||
err = -EINVAL;
|
||||
err = -errno;
|
||||
pr_warn_elf("failed to write ELF contents");
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
elf_end(linker->elf);
|
||||
linker->elf = NULL;
|
||||
close(linker->fd);
|
||||
|
||||
if (linker->fd_is_owned)
|
||||
close(linker->fd);
|
||||
linker->elf = NULL;
|
||||
linker->fd = -1;
|
||||
|
||||
return 0;
|
||||
@@ -2857,7 +2651,6 @@ static int emit_elf_data_sec(struct bpf_linker *linker, const char *sec_name,
|
||||
|
||||
static int finalize_btf(struct bpf_linker *linker)
|
||||
{
|
||||
enum btf_endianness link_endianness;
|
||||
LIBBPF_OPTS(btf_dedup_opts, opts);
|
||||
struct btf *btf = linker->btf;
|
||||
const void *raw_data;
|
||||
@@ -2891,24 +2684,17 @@ static int finalize_btf(struct bpf_linker *linker)
|
||||
|
||||
err = finalize_btf_ext(linker);
|
||||
if (err) {
|
||||
pr_warn(".BTF.ext generation failed: %s\n", errstr(err));
|
||||
pr_warn(".BTF.ext generation failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
opts.btf_ext = linker->btf_ext;
|
||||
err = btf__dedup(linker->btf, &opts);
|
||||
if (err) {
|
||||
pr_warn("BTF dedup failed: %s\n", errstr(err));
|
||||
pr_warn("BTF dedup failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set .BTF and .BTF.ext output byte order */
|
||||
link_endianness = linker->elf_hdr->e_ident[EI_DATA] == ELFDATA2MSB ?
|
||||
BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
|
||||
btf__set_endianness(linker->btf, link_endianness);
|
||||
if (linker->btf_ext)
|
||||
btf_ext__set_endianness(linker->btf_ext, link_endianness);
|
||||
|
||||
/* Emit .BTF section */
|
||||
raw_data = btf__raw_data(linker->btf, &raw_sz);
|
||||
if (!raw_data)
|
||||
@@ -2916,19 +2702,19 @@ static int finalize_btf(struct bpf_linker *linker)
|
||||
|
||||
err = emit_elf_data_sec(linker, BTF_ELF_SEC, 8, raw_data, raw_sz);
|
||||
if (err) {
|
||||
pr_warn("failed to write out .BTF ELF section: %s\n", errstr(err));
|
||||
pr_warn("failed to write out .BTF ELF section: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Emit .BTF.ext section */
|
||||
if (linker->btf_ext) {
|
||||
raw_data = btf_ext__raw_data(linker->btf_ext, &raw_sz);
|
||||
raw_data = btf_ext__get_raw_data(linker->btf_ext, &raw_sz);
|
||||
if (!raw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
err = emit_elf_data_sec(linker, BTF_EXT_ELF_SEC, 8, raw_data, raw_sz);
|
||||
if (err) {
|
||||
pr_warn("failed to write out .BTF.ext ELF section: %s\n", errstr(err));
|
||||
pr_warn("failed to write out .BTF.ext ELF section: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -3104,7 +2890,7 @@ static int finalize_btf_ext(struct bpf_linker *linker)
|
||||
err = libbpf_get_error(linker->btf_ext);
|
||||
if (err) {
|
||||
linker->btf_ext = NULL;
|
||||
pr_warn("failed to parse final .BTF.ext data: %s\n", errstr(err));
|
||||
pr_warn("failed to parse final .BTF.ext data: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
131
src/netlink.c
131
src/netlink.c
@@ -9,7 +9,6 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/netdev.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
@@ -40,16 +39,9 @@ struct xdp_id_md {
|
||||
int ifindex;
|
||||
__u32 flags;
|
||||
struct xdp_link_info info;
|
||||
__u64 feature_flags;
|
||||
};
|
||||
|
||||
struct xdp_features_md {
|
||||
int ifindex;
|
||||
__u32 xdp_zc_max_segs;
|
||||
__u64 flags;
|
||||
};
|
||||
|
||||
static int libbpf_netlink_open(__u32 *nl_pid, int proto)
|
||||
static int libbpf_netlink_open(__u32 *nl_pid)
|
||||
{
|
||||
struct sockaddr_nl sa;
|
||||
socklen_t addrlen;
|
||||
@@ -59,7 +51,7 @@ static int libbpf_netlink_open(__u32 *nl_pid, int proto)
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
|
||||
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
|
||||
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -220,14 +212,14 @@ done:
|
||||
}
|
||||
|
||||
static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
|
||||
int proto, __dump_nlmsg_t parse_msg,
|
||||
__dump_nlmsg_t parse_msg,
|
||||
libbpf_dump_nlmsg_t parse_attr,
|
||||
void *cookie)
|
||||
{
|
||||
__u32 nl_pid = 0;
|
||||
int sock, ret;
|
||||
|
||||
sock = libbpf_netlink_open(&nl_pid, proto);
|
||||
sock = libbpf_netlink_open(&nl_pid);
|
||||
if (sock < 0)
|
||||
return sock;
|
||||
|
||||
@@ -246,43 +238,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_genl_family_id(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||
void *cookie)
|
||||
{
|
||||
struct genlmsghdr *gnl = NLMSG_DATA(nh);
|
||||
struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
|
||||
struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
|
||||
__u16 *id = cookie;
|
||||
|
||||
libbpf_nla_parse(tb, CTRL_ATTR_FAMILY_ID, na,
|
||||
NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
|
||||
if (!tb[CTRL_ATTR_FAMILY_ID])
|
||||
return NL_CONT;
|
||||
|
||||
*id = libbpf_nla_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
return NL_DONE;
|
||||
}
|
||||
|
||||
static int libbpf_netlink_resolve_genl_family_id(const char *name,
|
||||
__u16 len, __u16 *id)
|
||||
{
|
||||
struct libbpf_nla_req req = {
|
||||
.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN),
|
||||
.nh.nlmsg_type = GENL_ID_CTRL,
|
||||
.nh.nlmsg_flags = NLM_F_REQUEST,
|
||||
.gnl.cmd = CTRL_CMD_GETFAMILY,
|
||||
.gnl.version = 2,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = nlattr_add(&req, CTRL_ATTR_FAMILY_NAME, name, len);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
|
||||
parse_genl_family_id, NULL, id);
|
||||
}
|
||||
|
||||
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
||||
__u32 flags)
|
||||
{
|
||||
@@ -316,7 +271,7 @@ static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
||||
}
|
||||
nlattr_end_nested(&req, nla);
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts)
|
||||
@@ -402,32 +357,6 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||
void *cookie)
|
||||
{
|
||||
struct genlmsghdr *gnl = NLMSG_DATA(nh);
|
||||
struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN);
|
||||
struct nlattr *tb[NETDEV_CMD_MAX + 1];
|
||||
struct xdp_features_md *md = cookie;
|
||||
__u32 ifindex;
|
||||
|
||||
libbpf_nla_parse(tb, NETDEV_CMD_MAX, na,
|
||||
NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL);
|
||||
|
||||
if (!tb[NETDEV_A_DEV_IFINDEX] || !tb[NETDEV_A_DEV_XDP_FEATURES])
|
||||
return NL_CONT;
|
||||
|
||||
ifindex = libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_IFINDEX]);
|
||||
if (ifindex != md->ifindex)
|
||||
return NL_CONT;
|
||||
|
||||
md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]);
|
||||
if (tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS])
|
||||
md->xdp_zc_max_segs =
|
||||
libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_XDP_ZC_MAX_SEGS]);
|
||||
return NL_DONE;
|
||||
}
|
||||
|
||||
int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
{
|
||||
struct libbpf_nla_req req = {
|
||||
@@ -437,10 +366,6 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
.ifinfo.ifi_family = AF_PACKET,
|
||||
};
|
||||
struct xdp_id_md xdp_id = {};
|
||||
struct xdp_features_md md = {
|
||||
.ifindex = ifindex,
|
||||
};
|
||||
__u16 id;
|
||||
int err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_xdp_query_opts))
|
||||
@@ -457,7 +382,7 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
xdp_id.ifindex = ifindex;
|
||||
xdp_id.flags = xdp_flags;
|
||||
|
||||
err = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, __dump_link_nlmsg,
|
||||
err = libbpf_netlink_send_recv(&req, __dump_link_nlmsg,
|
||||
get_xdp_info, &xdp_id);
|
||||
if (err)
|
||||
return libbpf_err(err);
|
||||
@@ -468,38 +393,6 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id);
|
||||
OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode);
|
||||
|
||||
if (!OPTS_HAS(opts, feature_flags))
|
||||
return 0;
|
||||
|
||||
err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id);
|
||||
if (err < 0) {
|
||||
if (err == -ENOENT) {
|
||||
opts->feature_flags = 0;
|
||||
goto skip_feature_flags;
|
||||
}
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST;
|
||||
req.nh.nlmsg_type = id;
|
||||
req.gnl.cmd = NETDEV_CMD_DEV_GET;
|
||||
req.gnl.version = 2;
|
||||
|
||||
err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex));
|
||||
if (err < 0)
|
||||
return libbpf_err(err);
|
||||
|
||||
err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC,
|
||||
parse_xdp_features, NULL, &md);
|
||||
if (err)
|
||||
return libbpf_err(err);
|
||||
|
||||
OPTS_SET(opts, feature_flags, md.flags);
|
||||
OPTS_SET(opts, xdp_zc_max_segs, md.xdp_zc_max_segs);
|
||||
|
||||
skip_feature_flags:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -600,7 +493,7 @@ static int tc_qdisc_modify(struct bpf_tc_hook *hook, int cmd, int flags)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
|
||||
@@ -700,7 +593,7 @@ static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
|
||||
int len, ret;
|
||||
|
||||
memset(&info, 0, info_len);
|
||||
ret = bpf_prog_get_info_by_fd(fd, &info, &info_len);
|
||||
ret = bpf_obj_get_info_by_fd(fd, &info, &info_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -780,8 +673,7 @@ int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||
|
||||
info.opts = opts;
|
||||
|
||||
ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
|
||||
&info);
|
||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
if (!info.processed)
|
||||
@@ -847,7 +739,7 @@ static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NETLINK_ROUTE, NULL, NULL, NULL);
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||
@@ -912,8 +804,7 @@ int bpf_tc_query(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||
|
||||
info.opts = opts;
|
||||
|
||||
ret = libbpf_netlink_send_recv(&req, NETLINK_ROUTE, get_tc_info, NULL,
|
||||
&info);
|
||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
if (!info.processed)
|
||||
|
||||
19
src/nlattr.c
19
src/nlattr.c
@@ -32,7 +32,7 @@ static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
|
||||
|
||||
static int nla_ok(const struct nlattr *nla, int remaining)
|
||||
{
|
||||
return remaining >= (int)sizeof(*nla) &&
|
||||
return remaining >= sizeof(*nla) &&
|
||||
nla->nla_len >= sizeof(*nla) &&
|
||||
nla->nla_len <= remaining;
|
||||
}
|
||||
@@ -63,16 +63,16 @@ static int validate_nla(struct nlattr *nla, int maxtype,
|
||||
minlen = nla_attr_minlen[pt->type];
|
||||
|
||||
if (libbpf_nla_len(nla) < minlen)
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
|
||||
if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
|
||||
if (pt->type == LIBBPF_NLA_STRING) {
|
||||
char *data = libbpf_nla_data(nla);
|
||||
|
||||
if (data[libbpf_nla_len(nla) - 1] != '\0')
|
||||
return -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -118,18 +118,19 @@ int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
|
||||
if (policy) {
|
||||
err = validate_nla(nla, maxtype, policy);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (tb[type]) {
|
||||
if (tb[type])
|
||||
pr_warn("Attribute of type %#x found multiple times in message, "
|
||||
"previous attribute is being ignored.\n", type);
|
||||
}
|
||||
|
||||
tb[type] = nla;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err = 0;
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +178,7 @@ int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
|
||||
hlen += nlmsg_len(&err->msg);
|
||||
|
||||
attr = (struct nlattr *) ((void *) err + hlen);
|
||||
alen = (void *)nlh + nlh->nlmsg_len - (void *)attr;
|
||||
alen = nlh->nlmsg_len - hlen;
|
||||
|
||||
if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
|
||||
extack_policy) != 0) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user