mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-14 13:29:06 +08:00
Compare commits
27 Commits
master
...
netdata_pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d78a726c6 | ||
|
|
7d1fe77f65 | ||
|
|
89aecd2188 | ||
|
|
b39b7f426f | ||
|
|
b981a3a138 | ||
|
|
f8f9df60e0 | ||
|
|
360a2fd909 | ||
|
|
8b905090e8 | ||
|
|
dd7dd01114 | ||
|
|
a16e904d6c | ||
|
|
dac1c4b6a8 | ||
|
|
862b60f205 | ||
|
|
70599f3a1e | ||
|
|
e4f2e6e865 | ||
|
|
74c16e9a0c | ||
|
|
e61e089911 | ||
|
|
b9d46530c3 | ||
|
|
86175df408 | ||
|
|
720324afab | ||
|
|
aea40f7179 | ||
|
|
54a7bc87d5 | ||
|
|
9979463ccf | ||
|
|
b91ca01922 | ||
|
|
8ded7c6db0 | ||
|
|
7df4ea0f0d | ||
|
|
02333ba360 | ||
|
|
6921017d25 |
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
|
||||
60
.github/actions/build-selftests/build_selftests.sh
vendored
Executable file
60
.github/actions/build-selftests/build_selftests.sh
vendored
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
THISDIR="$(cd $(dirname $0) && pwd)"
|
||||
|
||||
source ${THISDIR}/helpers.sh
|
||||
|
||||
foldable start prepare_selftests "Building selftests"
|
||||
|
||||
LIBBPF_PATH="${REPO_ROOT}"
|
||||
|
||||
llvm_default_version() {
|
||||
echo "16"
|
||||
}
|
||||
|
||||
llvm_latest_version() {
|
||||
echo "17"
|
||||
}
|
||||
|
||||
LLVM_VERSION=$(llvm_default_version)
|
||||
if [[ "${LLVM_VERSION}" == $(llvm_latest_version) ]]; then
|
||||
REPO_DISTRO_SUFFIX=""
|
||||
else
|
||||
REPO_DISTRO_SUFFIX="-${LLVM_VERSION}"
|
||||
fi
|
||||
|
||||
echo "deb https://apt.llvm.org/focal/ llvm-toolchain-focal${REPO_DISTRO_SUFFIX} main" \
|
||||
| sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
|
||||
PREPARE_SELFTESTS_SCRIPT=${THISDIR}/prepare_selftests-${KERNEL}.sh
|
||||
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 headers
|
||||
make \
|
||||
CLANG=clang-${LLVM_VERSION} \
|
||||
LLC=llc-${LLVM_VERSION} \
|
||||
LLVM_STRIP=llvm-strip-${LLVM_VERSION} \
|
||||
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
|
||||
38
.github/actions/build-selftests/helpers.sh
vendored
Normal file
38
.github/actions/build-selftests/helpers.sh
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# shellcheck shell=bash
|
||||
|
||||
# $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
|
||||
}
|
||||
5
.github/actions/build-selftests/prepare_selftests-4.9.0.sh
vendored
Executable file
5
.github/actions/build-selftests/prepare_selftests-4.9.0.sh
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
printf "all:\n\ttouch bpf_test_no_cfi.ko\n\nclean:\n" > bpf_test_no_cfi/Makefile
|
||||
|
||||
5
.github/actions/build-selftests/prepare_selftests-5.5.0.sh
vendored
Executable file
5
.github/actions/build-selftests/prepare_selftests-5.5.0.sh
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
printf "all:\n\ttouch bpf_test_no_cfi.ko\n\nclean:\n" > bpf_test_no_cfi/Makefile
|
||||
|
||||
17834
.github/actions/build-selftests/vmlinux.h
vendored
17834
.github/actions/build-selftests/vmlinux.h
vendored
File diff suppressed because it is too large
Load Diff
118
.github/actions/vmtest/action.yml
vendored
Normal file
118
.github/actions/vmtest/action.yml
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
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:
|
||||
# Allow CI user to access /dev/kvm (via qemu) w/o group change/relogin
|
||||
# by changing permissions set by udev.
|
||||
- name: Set /dev/kvm permissions
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -e /dev/kvm ]; then
|
||||
echo "/dev/kvm exists"
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
|
||||
| sudo tee /etc/udev/rules.d/99-kvm4all.rules > /dev/null
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
fi
|
||||
else
|
||||
echo "/dev/kvm does not exist"
|
||||
fi
|
||||
# setup environment
|
||||
- name: Setup environment
|
||||
uses: libbpf/ci/setup-build-env@main
|
||||
with:
|
||||
pahole: ${{ inputs.pahole }}
|
||||
arch: ${{ inputs.arch }}
|
||||
# 1. download CHECKPOINT kernel source
|
||||
- name: Get checkpoint commit
|
||||
shell: bash
|
||||
run: |
|
||||
cat CHECKPOINT-COMMIT
|
||||
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
||||
- name: Get kernel source at checkpoint
|
||||
uses: libbpf/ci/get-linux-source@main
|
||||
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@main
|
||||
with:
|
||||
patches-root: '${{ github.workspace }}/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
|
||||
# this file might or mihgt not exist depending on kernel version
|
||||
cat tools/testing/selftests/bpf/config.vm >> .config || :
|
||||
make olddefconfig && make prepare
|
||||
cd -
|
||||
foldable end
|
||||
# 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@main
|
||||
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@main
|
||||
env:
|
||||
KBUILD_OUTPUT: '.kernel'
|
||||
with:
|
||||
project-name: 'libbpf'
|
||||
arch: ${{ inputs.arch }}
|
||||
kernel: ${{ inputs.kernel }}
|
||||
kernel-root: '.kernel'
|
||||
kbuild-output: ${{ env.KBUILD_OUTPUT }}
|
||||
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@main
|
||||
with:
|
||||
arch: ${{ inputs.arch }}
|
||||
img: '/tmp/root.img'
|
||||
vmlinuz: 'vmlinuz'
|
||||
kernel-root: '.kernel'
|
||||
43
.github/workflows/build.yml
vendored
43
.github/workflows/build.yml
vendored
@@ -61,32 +61,31 @@ jobs:
|
||||
- arch: aarch64
|
||||
- arch: ppc64le
|
||||
- arch: s390x
|
||||
- arch: amd64
|
||||
- arch: x86
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
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.7.1
|
||||
name: Build in docker
|
||||
if: matrix.arch != 'x86'
|
||||
with:
|
||||
distro:
|
||||
ubuntu22.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
|
||||
|
||||
12
.github/workflows/coverity.yml
vendored
12
.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: ./.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'
|
||||
|
||||
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@v4
|
||||
- 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@v4
|
||||
- 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-20.04
|
||||
arch: 'x86_64'
|
||||
- kernel: '5.5.0'
|
||||
runs_on: ubuntu-20.04
|
||||
arch: 'x86_64'
|
||||
- kernel: '4.9.0'
|
||||
runs_on: ubuntu-20.04
|
||||
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: s390x
|
||||
arch: 's390x'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
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 }}
|
||||
|
||||
4
.mailmap
4
.mailmap
@@ -8,8 +8,6 @@ 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>
|
||||
@@ -17,6 +15,4 @@ 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>
|
||||
|
||||
@@ -1 +1 @@
|
||||
b4432656b36e5cc1d50a1f2dc15357543add530e
|
||||
62da3acd28955e7299babebdfcb14243b789e773
|
||||
|
||||
@@ -1 +1 @@
|
||||
9325d53fe9adff354b6a93fda5f38c165947da0f
|
||||
531876c80004ecff7bfdbd8ba6c6b48835ef5e22
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,69 @@
|
||||
From c71766e8ff7a7f950522d25896fba758585500df Mon Sep 17 00:00:00 2001
|
||||
From: Song Liu <song@kernel.org>
|
||||
Date: Mon, 22 Apr 2024 21:14:40 -0700
|
||||
Subject: [PATCH] arch/Kconfig: Move SPECULATION_MITIGATIONS to arch/Kconfig
|
||||
|
||||
SPECULATION_MITIGATIONS is currently defined only for x86. As a result,
|
||||
IS_ENABLED(CONFIG_SPECULATION_MITIGATIONS) is always false for other
|
||||
archs. f337a6a21e2f effectively set "mitigations=off" by default on
|
||||
non-x86 archs, which is not desired behavior. Jakub observed this
|
||||
change when running bpf selftests on s390 and arm64.
|
||||
|
||||
Fix this by moving SPECULATION_MITIGATIONS to arch/Kconfig so that it is
|
||||
available in all archs and thus can be used safely in kernel/cpu.c
|
||||
|
||||
Fixes: f337a6a21e2f ("x86/cpu: Actually turn off mitigations by default for SPECULATION_MITIGATIONS=n")
|
||||
Cc: stable@vger.kernel.org
|
||||
Cc: Sean Christopherson <seanjc@google.com>
|
||||
Cc: Ingo Molnar <mingo@kernel.org>
|
||||
Cc: Daniel Sneddon <daniel.sneddon@linux.intel.com>
|
||||
Cc: Jakub Kicinski <kuba@kernel.org>
|
||||
Signed-off-by: Song Liu <song@kernel.org>
|
||||
---
|
||||
arch/Kconfig | 10 ++++++++++
|
||||
arch/x86/Kconfig | 10 ----------
|
||||
2 files changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/arch/Kconfig b/arch/Kconfig
|
||||
index 9f066785bb71..8f4af75005f8 100644
|
||||
--- a/arch/Kconfig
|
||||
+++ b/arch/Kconfig
|
||||
@@ -1609,4 +1609,14 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT
|
||||
# strict alignment always, even with -falign-functions.
|
||||
def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG
|
||||
|
||||
+menuconfig SPECULATION_MITIGATIONS
|
||||
+ bool "Mitigations for speculative execution vulnerabilities"
|
||||
+ default y
|
||||
+ help
|
||||
+ Say Y here to enable options which enable mitigations for
|
||||
+ speculative execution hardware vulnerabilities.
|
||||
+
|
||||
+ If you say N, all mitigations will be disabled. You really
|
||||
+ should know what you are doing to say so.
|
||||
+
|
||||
endmenu
|
||||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
||||
index 39886bab943a..50c890fce5e0 100644
|
||||
--- a/arch/x86/Kconfig
|
||||
+++ b/arch/x86/Kconfig
|
||||
@@ -2486,16 +2486,6 @@ config PREFIX_SYMBOLS
|
||||
def_bool y
|
||||
depends on CALL_PADDING && !CFI_CLANG
|
||||
|
||||
-menuconfig SPECULATION_MITIGATIONS
|
||||
- bool "Mitigations for speculative execution vulnerabilities"
|
||||
- default y
|
||||
- help
|
||||
- Say Y here to enable options which enable mitigations for
|
||||
- speculative execution hardware vulnerabilities.
|
||||
-
|
||||
- If you say N, all mitigations will be disabled. You really
|
||||
- should know what you are doing to say so.
|
||||
-
|
||||
if SPECULATION_MITIGATIONS
|
||||
|
||||
config MITIGATION_PAGE_TABLE_ISOLATION
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
From 0daad0a615e687e1247230f3d0c31ae60ba32314 Mon Sep 17 00:00:00 2001
|
||||
From: Andrii Nakryiko <andrii@kernel.org>
|
||||
Date: Tue, 28 May 2024 15:29:38 -0700
|
||||
Subject: [PATCH bpf-next] selftests/bpf: fix inet_csk_accept prototype in
|
||||
test_sk_storage_tracing.c
|
||||
|
||||
Recent kernel change ([0]) changed inet_csk_accept() prototype. Adapt
|
||||
progs/test_sk_storage_tracing.c to take that into account.
|
||||
|
||||
[0] 92ef0fd55ac8 ("net: change proto and proto_ops accept type")
|
||||
|
||||
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
|
||||
---
|
||||
tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c b/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c
|
||||
index 02e718f06e0f..40531e56776e 100644
|
||||
--- a/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c
|
||||
+++ b/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c
|
||||
@@ -84,7 +84,7 @@ int BPF_PROG(trace_tcp_connect, struct sock *sk)
|
||||
}
|
||||
|
||||
SEC("fexit/inet_csk_accept")
|
||||
-int BPF_PROG(inet_csk_accept, struct sock *sk, int flags, int *err, bool kern,
|
||||
+int BPF_PROG(inet_csk_accept, struct sock *sk, struct proto_accept_arg *arg,
|
||||
struct sock *accepted_sk)
|
||||
{
|
||||
set_task_info(accepted_sk);
|
||||
--
|
||||
2.43.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
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
From f267f262815033452195f46c43b572159262f533 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Date: Tue, 5 Mar 2024 10:08:28 +0100
|
||||
Subject: [PATCH 2/2] xdp, bonding: Fix feature flags when there are no slave
|
||||
devs anymore
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Commit 9b0ed890ac2a ("bonding: do not report NETDEV_XDP_ACT_XSK_ZEROCOPY")
|
||||
changed the driver from reporting everything as supported before a device
|
||||
was bonded into having the driver report that no XDP feature is supported
|
||||
until a real device is bonded as it seems to be more truthful given
|
||||
eventually real underlying devices decide what XDP features are supported.
|
||||
|
||||
The change however did not take into account when all slave devices get
|
||||
removed from the bond device. In this case after 9b0ed890ac2a, the driver
|
||||
keeps reporting a feature mask of 0x77, that is, NETDEV_XDP_ACT_MASK &
|
||||
~NETDEV_XDP_ACT_XSK_ZEROCOPY whereas it should have reported a feature
|
||||
mask of 0.
|
||||
|
||||
Fix it by resetting XDP feature flags in the same way as if no XDP program
|
||||
is attached to the bond device. This was uncovered by the XDP bond selftest
|
||||
which let BPF CI fail. After adjusting the starting masks on the latter
|
||||
to 0 instead of NETDEV_XDP_ACT_MASK the test passes again together with
|
||||
this fix.
|
||||
|
||||
Fixes: 9b0ed890ac2a ("bonding: do not report NETDEV_XDP_ACT_XSK_ZEROCOPY")
|
||||
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Cc: Magnus Karlsson <magnus.karlsson@intel.com>
|
||||
Cc: Prashant Batra <prbatra.mail@gmail.com>
|
||||
Cc: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Cc: Jakub Kicinski <kuba@kernel.org>
|
||||
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Message-ID: <20240305090829.17131-1-daniel@iogearbox.net>
|
||||
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||||
---
|
||||
drivers/net/bonding/bond_main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
||||
index a11748b8d69b..cd0683bcca03 100644
|
||||
--- a/drivers/net/bonding/bond_main.c
|
||||
+++ b/drivers/net/bonding/bond_main.c
|
||||
@@ -1811,7 +1811,7 @@ void bond_xdp_set_features(struct net_device *bond_dev)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
- if (!bond_xdp_check(bond)) {
|
||||
+ if (!bond_xdp_check(bond) || !bond_has_slaves(bond)) {
|
||||
xdp_clear_features_flag(bond_dev);
|
||||
return;
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
|
||||
49
ci/vmtest/configs/ALLOWLIST-5.5.0
Normal file
49
ci/vmtest/configs/ALLOWLIST-5.5.0
Normal file
@@ -0,0 +1,49 @@
|
||||
# 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
|
||||
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
|
||||
sockmap_ktls
|
||||
spinlock
|
||||
stacktrace_map
|
||||
stacktrace_map_raw_tp
|
||||
static_linked
|
||||
task_fd_query_rawtp
|
||||
task_fd_query_tp
|
||||
tc_bpf
|
||||
tcp_estats
|
||||
test_global_funcs/arg_tag_ctx*
|
||||
tp_attach_query
|
||||
usdt/urand_pid_attach
|
||||
xdp
|
||||
xdp_noinline
|
||||
xdp_perf
|
||||
@@ -12,4 +12,3 @@ xdp_bonding/xdp_bonding_features # started failing after net merge from 359e
|
||||
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
|
||||
|
||||
5
ci/vmtest/configs/DENYLIST-5.5.0
Normal file
5
ci/vmtest/configs/DENYLIST-5.5.0
Normal file
@@ -0,0 +1,5 @@
|
||||
# This complements ALLOWLIST-5.5.0 but excludes subtest that can't work on 5.5
|
||||
|
||||
btf # "size check test", "func (Non zero vlen)"
|
||||
tailcalls # tailcall_bpf2bpf_1, tailcall_bpf2bpf_2, tailcall_bpf2bpf_3
|
||||
tc_bpf/tc_bpf_non_root
|
||||
@@ -1,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"
|
||||
38
ci/vmtest/helpers.sh
Executable file
38
ci/vmtest/helpers.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
# shellcheck shell=bash
|
||||
|
||||
# $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
|
||||
}
|
||||
94
ci/vmtest/run_selftests.sh
Executable file
94
ci/vmtest/run_selftests.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/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 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | tr -s '\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
|
||||
|
||||
foldable start kernel_config "Kconfig"
|
||||
|
||||
zcat /proc/config.gz
|
||||
|
||||
foldable end kernel_config
|
||||
|
||||
|
||||
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
|
||||
@@ -121,8 +121,6 @@ described in more detail in the footnotes.
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``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]_ | |
|
||||
@@ -133,23 +131,11 @@ described in more detail in the footnotes.
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``raw_tracepoint+`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SCHED_ACT`` | | ``action`` [#tc_legacy]_ | |
|
||||
| ``BPF_PROG_TYPE_SCHED_ACT`` | | ``action`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SCHED_CLS`` | | ``classifier`` [#tc_legacy]_ | |
|
||||
| ``BPF_PROG_TYPE_SCHED_CLS`` | | ``classifier`` | |
|
||||
+ + +----------------------------------+-----------+
|
||||
| | | ``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`` | |
|
||||
| | | ``tc`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SK_LOOKUP`` | ``BPF_SK_LOOKUP`` | ``sk_lookup`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
@@ -169,9 +155,7 @@ described in more detail in the footnotes.
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``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_STRUCT_OPS`` | | ``struct_ops+`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_SYSCALL`` | | ``syscall`` | Yes |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
@@ -225,11 +209,5 @@ described in more detail in the footnotes.
|
||||
``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>``.
|
||||
|
||||
@@ -51,9 +51,6 @@
|
||||
#define BPF_XCHG (0xe0 | BPF_FETCH) /* atomic exchange */
|
||||
#define BPF_CMPXCHG (0xf0 | BPF_FETCH) /* atomic compare-and-write */
|
||||
|
||||
#define BPF_LOAD_ACQ 0x100 /* load-acquire */
|
||||
#define BPF_STORE_REL 0x110 /* store-release */
|
||||
|
||||
enum bpf_cond_pseudo_jmp {
|
||||
BPF_MAY_GOTO = 0,
|
||||
};
|
||||
@@ -1119,15 +1116,11 @@ enum bpf_attach_type {
|
||||
BPF_NETKIT_PRIMARY,
|
||||
BPF_NETKIT_PEER,
|
||||
BPF_TRACE_KPROBE_SESSION,
|
||||
BPF_TRACE_UPROBE_SESSION,
|
||||
__MAX_BPF_ATTACH_TYPE
|
||||
};
|
||||
|
||||
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
|
||||
|
||||
/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
|
||||
* in sync with the definitions below.
|
||||
*/
|
||||
enum bpf_link_type {
|
||||
BPF_LINK_TYPE_UNSPEC = 0,
|
||||
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
|
||||
@@ -1210,7 +1203,6 @@ enum bpf_perf_event_type {
|
||||
#define BPF_F_BEFORE (1U << 3)
|
||||
#define BPF_F_AFTER (1U << 4)
|
||||
#define BPF_F_ID (1U << 5)
|
||||
#define BPF_F_PREORDER (1U << 6)
|
||||
#define BPF_F_LINK BPF_F_LINK /* 1 << 13 */
|
||||
|
||||
/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
|
||||
@@ -1433,8 +1425,6 @@ enum {
|
||||
#define BPF_F_TEST_RUN_ON_CPU (1U << 0)
|
||||
/* If set, XDP frames will be transmitted after processing */
|
||||
#define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1)
|
||||
/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */
|
||||
#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2)
|
||||
|
||||
/* type for BPF_ENABLE_STATS */
|
||||
enum bpf_stats_type {
|
||||
@@ -1506,7 +1496,7 @@ union bpf_attr {
|
||||
__s32 map_token_fd;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM and BPF_MAP_FREEZE commands */
|
||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||
__u32 map_fd;
|
||||
__aligned_u64 key;
|
||||
union {
|
||||
@@ -1577,16 +1567,6 @@ union bpf_attr {
|
||||
* If provided, prog_flags should have BPF_F_TOKEN_FD flag set.
|
||||
*/
|
||||
__s32 prog_token_fd;
|
||||
/* The fd_array_cnt can be used to pass the length of the
|
||||
* fd_array array. In this case all the [map] file descriptors
|
||||
* passed in this array will be bound to the program, even if
|
||||
* the maps are not referenced directly. The functionality is
|
||||
* similar to the BPF_PROG_BIND_MAP syscall, but maps can be
|
||||
* used by the verifier during the program load. If provided,
|
||||
* then the fd_array[0,...,fd_array_cnt-1] is expected to be
|
||||
* continuous.
|
||||
*/
|
||||
__u32 fd_array_cnt;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||
@@ -1652,7 +1632,6 @@ union bpf_attr {
|
||||
};
|
||||
__u32 next_id;
|
||||
__u32 open_flags;
|
||||
__s32 fd_by_id_token_fd;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
|
||||
@@ -1989,21 +1968,15 @@ union bpf_attr {
|
||||
* program.
|
||||
* Return
|
||||
* The SMP id of the processor running the program.
|
||||
* Attributes
|
||||
* __bpf_fastcall
|
||||
*
|
||||
* long bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags)
|
||||
* Description
|
||||
* Store *len* bytes from address *from* into the packet
|
||||
* associated to *skb*, at *offset*. The *flags* are a combination
|
||||
* of the following values:
|
||||
*
|
||||
* **BPF_F_RECOMPUTE_CSUM**
|
||||
* Automatically update *skb*\ **->csum** after storing the
|
||||
* bytes.
|
||||
* **BPF_F_INVALIDATE_HASH**
|
||||
* Set *skb*\ **->hash**, *skb*\ **->swhash** and *skb*\
|
||||
* **->l4hash** to 0.
|
||||
* associated to *skb*, at *offset*. *flags* are a combination of
|
||||
* **BPF_F_RECOMPUTE_CSUM** (automatically recompute the
|
||||
* checksum for the packet after storing the bytes) and
|
||||
* **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\
|
||||
* **->swhash** and *skb*\ **->l4hash** to 0).
|
||||
*
|
||||
* A call to this helper is susceptible to change the underlying
|
||||
* packet buffer. Therefore, at load time, all checks on pointers
|
||||
@@ -2055,7 +2028,7 @@ union bpf_attr {
|
||||
* untouched (unless **BPF_F_MARK_ENFORCE** is added as well), and
|
||||
* for updates resulting in a null checksum the value is set to
|
||||
* **CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates
|
||||
* that the modified header field is part of the pseudo-header.
|
||||
* the checksum is to be computed against a pseudo-header.
|
||||
*
|
||||
* This helper works in combination with **bpf_csum_diff**\ (),
|
||||
* which does not update the checksum in-place, but offers more
|
||||
@@ -2876,7 +2849,7 @@ union bpf_attr {
|
||||
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
|
||||
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
|
||||
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
|
||||
* **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**.
|
||||
* **TCP_BPF_RTO_MIN**.
|
||||
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
||||
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
|
||||
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
|
||||
@@ -3126,6 +3099,10 @@ union bpf_attr {
|
||||
* with the **CONFIG_BPF_KPROBE_OVERRIDE** configuration
|
||||
* option, and in this case it only works on functions tagged with
|
||||
* **ALLOW_ERROR_INJECTION** in the kernel code.
|
||||
*
|
||||
* Also, the helper is only available for the architectures having
|
||||
* the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing,
|
||||
* x86 architecture is the only one to support this feature.
|
||||
* Return
|
||||
* 0
|
||||
*
|
||||
@@ -5390,7 +5367,7 @@ union bpf_attr {
|
||||
* Currently, the **flags** must be 0. Currently, nr_loops is
|
||||
* limited to 1 << 23 (~8 million) loops.
|
||||
*
|
||||
* long (\*callback_fn)(u64 index, void \*ctx);
|
||||
* long (\*callback_fn)(u32 index, void \*ctx);
|
||||
*
|
||||
* where **index** is the current index in the loop. The index
|
||||
* is zero-indexed.
|
||||
@@ -5540,12 +5517,11 @@ union bpf_attr {
|
||||
* **-EOPNOTSUPP** if the hash calculation failed or **-EINVAL** if
|
||||
* invalid arguments are passed.
|
||||
*
|
||||
* void *bpf_kptr_xchg(void *dst, void *ptr)
|
||||
* void *bpf_kptr_xchg(void *map_value, void *ptr)
|
||||
* Description
|
||||
* Exchange kptr at pointer *dst* with *ptr*, and return the old value.
|
||||
* *dst* can be map value or local kptr. *ptr* can be NULL, otherwise
|
||||
* it must be a referenced pointer which will be released when this helper
|
||||
* is called.
|
||||
* Exchange kptr at pointer *map_value* with *ptr*, and return the
|
||||
* old value. *ptr* can be NULL, otherwise it must be a referenced
|
||||
* pointer which will be released when this helper is called.
|
||||
* Return
|
||||
* The old value of kptr (which can be NULL). The returned pointer
|
||||
* if not NULL, is a reference which must be released using its
|
||||
@@ -6028,10 +6004,7 @@ union bpf_attr {
|
||||
FN(user_ringbuf_drain, 209, ##ctx) \
|
||||
FN(cgrp_storage_get, 210, ##ctx) \
|
||||
FN(cgrp_storage_delete, 211, ##ctx) \
|
||||
/* This helper list is effectively frozen. If you are trying to \
|
||||
* add a new helper, you should add a kfunc instead which has \
|
||||
* less stability guarantees. See Documentation/bpf/kfuncs.rst \
|
||||
*/
|
||||
/* */
|
||||
|
||||
/* backwards-compatibility macros for users of __BPF_FUNC_MAPPER that don't
|
||||
* know or care about integer value that is now passed as second argument
|
||||
@@ -6071,6 +6044,11 @@ enum {
|
||||
BPF_F_MARK_ENFORCE = (1ULL << 6),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
|
||||
enum {
|
||||
BPF_F_INGRESS = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
|
||||
enum {
|
||||
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
|
||||
@@ -6217,12 +6195,10 @@ enum {
|
||||
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* Flags for bpf_redirect and bpf_redirect_map helpers */
|
||||
/* Flags for bpf_redirect_map helper */
|
||||
enum {
|
||||
BPF_F_INGRESS = (1ULL << 0), /* used for skb path */
|
||||
BPF_F_BROADCAST = (1ULL << 3), /* used for XDP path */
|
||||
BPF_F_EXCLUDE_INGRESS = (1ULL << 4), /* used for XDP path */
|
||||
#define BPF_F_REDIRECT_FLAGS (BPF_F_INGRESS | BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS)
|
||||
BPF_F_BROADCAST = (1ULL << 3),
|
||||
BPF_F_EXCLUDE_INGRESS = (1ULL << 4),
|
||||
};
|
||||
|
||||
#define __bpf_md_ptr(type, name) \
|
||||
@@ -6724,7 +6700,6 @@ struct bpf_link_info {
|
||||
__u32 name_len;
|
||||
__u32 offset; /* offset from file_name */
|
||||
__u64 cookie;
|
||||
__u64 ref_ctr_offset;
|
||||
} uprobe; /* BPF_PERF_EVENT_UPROBE, BPF_PERF_EVENT_URETPROBE */
|
||||
struct {
|
||||
__aligned_u64 func_name; /* in/out */
|
||||
@@ -6926,12 +6901,6 @@ enum {
|
||||
BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F,
|
||||
};
|
||||
|
||||
enum {
|
||||
SK_BPF_CB_TX_TIMESTAMPING = 1<<0,
|
||||
SK_BPF_CB_MASK = (SK_BPF_CB_TX_TIMESTAMPING - 1) |
|
||||
SK_BPF_CB_TX_TIMESTAMPING
|
||||
};
|
||||
|
||||
/* List of known BPF sock_ops operators.
|
||||
* New entries can only be added at the end
|
||||
*/
|
||||
@@ -7044,29 +7013,6 @@ enum {
|
||||
* by the kernel or the
|
||||
* earlier bpf-progs.
|
||||
*/
|
||||
BPF_SOCK_OPS_TSTAMP_SCHED_CB, /* Called when skb is passing
|
||||
* through dev layer when
|
||||
* SK_BPF_CB_TX_TIMESTAMPING
|
||||
* feature is on.
|
||||
*/
|
||||
BPF_SOCK_OPS_TSTAMP_SND_SW_CB, /* Called when skb is about to send
|
||||
* to the nic when SK_BPF_CB_TX_TIMESTAMPING
|
||||
* feature is on.
|
||||
*/
|
||||
BPF_SOCK_OPS_TSTAMP_SND_HW_CB, /* Called in hardware phase when
|
||||
* SK_BPF_CB_TX_TIMESTAMPING feature
|
||||
* is on.
|
||||
*/
|
||||
BPF_SOCK_OPS_TSTAMP_ACK_CB, /* Called when all the skbs in the
|
||||
* same sendmsg call are acked
|
||||
* when SK_BPF_CB_TX_TIMESTAMPING
|
||||
* feature is on.
|
||||
*/
|
||||
BPF_SOCK_OPS_TSTAMP_SENDMSG_CB, /* Called when every sendmsg syscall
|
||||
* is triggered. It's used to correlate
|
||||
* sendmsg timestamp with corresponding
|
||||
* tskey.
|
||||
*/
|
||||
};
|
||||
|
||||
/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
|
||||
@@ -7132,8 +7078,6 @@ enum {
|
||||
TCP_BPF_SYN = 1005, /* Copy the TCP header */
|
||||
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
|
||||
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
|
||||
TCP_BPF_SOCK_OPS_CB_FLAGS = 1008, /* Get or Set TCP sock ops flags */
|
||||
SK_BPF_CB_FLAGS = 1009, /* Get or set sock ops flags in socket */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -7566,13 +7510,4 @@ struct bpf_iter_num {
|
||||
__u64 __opaque[1];
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/*
|
||||
* Flags to control BPF kfunc behaviour.
|
||||
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
|
||||
* helper documentation for details.)
|
||||
*/
|
||||
enum bpf_kfunc_flags {
|
||||
BPF_F_PAD_ZEROS = (1ULL << 0),
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BPF_H__ */
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -377,7 +377,6 @@ enum {
|
||||
IFLA_GSO_IPV4_MAX_SIZE,
|
||||
IFLA_GRO_IPV4_MAX_SIZE,
|
||||
IFLA_DPLL_PIN,
|
||||
IFLA_MAX_PACING_OFFLOAD_HORIZON,
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
@@ -462,286 +461,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 +510,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 +520,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 */
|
||||
@@ -1293,19 +769,6 @@ enum netkit_mode {
|
||||
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,
|
||||
@@ -1313,10 +776,6 @@ enum {
|
||||
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)
|
||||
@@ -1395,7 +854,6 @@ enum {
|
||||
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 +871,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,
|
||||
@@ -1484,8 +935,6 @@ enum {
|
||||
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)
|
||||
@@ -1791,7 +1240,6 @@ enum {
|
||||
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
|
||||
* HSR. For example PRP.
|
||||
*/
|
||||
IFLA_HSR_INTERLINK, /* HSR interlink network device */
|
||||
__IFLA_HSR_MAX,
|
||||
};
|
||||
|
||||
@@ -1969,9 +1417,7 @@ enum {
|
||||
|
||||
enum {
|
||||
IFLA_DSA_UNSPEC,
|
||||
IFLA_DSA_CONDUIT,
|
||||
/* Deprecated, use IFLA_DSA_CONDUIT instead */
|
||||
IFLA_DSA_MASTER = IFLA_DSA_CONDUIT,
|
||||
IFLA_DSA_MASTER,
|
||||
__IFLA_DSA_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
*/
|
||||
#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)
|
||||
|
||||
struct sockaddr_xdp {
|
||||
__u16 sxdp_family;
|
||||
__u16 sxdp_flags;
|
||||
@@ -117,22 +113,16 @@ struct xdp_options {
|
||||
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||
|
||||
/* Request transmit timestamp. Upon completion, put it into tx_timestamp
|
||||
* field of struct xsk_tx_metadata.
|
||||
* field of union xsk_tx_metadata.
|
||||
*/
|
||||
#define XDP_TXMD_FLAGS_TIMESTAMP (1 << 0)
|
||||
|
||||
/* Request transmit checksum offload. Checksum start position and offset
|
||||
* are communicated via csum_start and csum_offset fields of struct
|
||||
* are communicated via csum_start and csum_offset fields of union
|
||||
* 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.
|
||||
@@ -148,10 +138,6 @@ struct xsk_tx_metadata {
|
||||
__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 {
|
||||
|
||||
@@ -59,13 +59,10 @@ enum netdev_xdp_rx_metadata {
|
||||
* 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 {
|
||||
@@ -89,11 +86,6 @@ enum {
|
||||
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,
|
||||
@@ -101,8 +93,6 @@ enum {
|
||||
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)
|
||||
@@ -131,27 +121,16 @@ enum {
|
||||
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)
|
||||
@@ -194,16 +173,6 @@ enum {
|
||||
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,
|
||||
@@ -217,8 +186,6 @@ enum {
|
||||
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)
|
||||
|
||||
@@ -385,8 +385,6 @@ enum perf_event_read_format {
|
||||
*
|
||||
* @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 +511,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
|
||||
@@ -1360,14 +1349,12 @@ 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 */
|
||||
/* 5-0x7 available */
|
||||
#define PERF_MEM_LVLNUM_UNC 0x08 /* Uncached */
|
||||
#define PERF_MEM_LVLNUM_CXL 0x09 /* CXL */
|
||||
#define PERF_MEM_LVLNUM_IO 0x0a /* I/O */
|
||||
#define PERF_MEM_LVLNUM_ANY_CACHE 0x0b /* Any cache */
|
||||
#define PERF_MEM_LVLNUM_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 */
|
||||
|
||||
13
src/Makefile
13
src/Makefile
@@ -9,7 +9,7 @@ else
|
||||
endif
|
||||
|
||||
LIBBPF_MAJOR_VERSION := 1
|
||||
LIBBPF_MINOR_VERSION := 6
|
||||
LIBBPF_MINOR_VERSION := 5
|
||||
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 = ..
|
||||
|
||||
@@ -42,12 +41,10 @@ ALL_CFLAGS += $(CFLAGS) \
|
||||
$(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 +55,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 zip.o elf.o features.o
|
||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||
|
||||
@@ -122,13 +119,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 $@
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, fd_array_cnt);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
|
||||
void *finfo = NULL, *linfo = NULL;
|
||||
const char *func_info, *line_info;
|
||||
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
||||
@@ -311,7 +311,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);
|
||||
@@ -777,7 +776,6 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
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));
|
||||
@@ -1097,7 +1095,7 @@ int bpf_map_get_fd_by_id(__u32 id)
|
||||
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);
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
@@ -1107,7 +1105,6 @@ int bpf_btf_get_fd_by_id_opts(__u32 id,
|
||||
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);
|
||||
|
||||
12
src/bpf.h
12
src/bpf.h
@@ -100,19 +100,16 @@ struct bpf_prog_load_opts {
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
char *log_buf;
|
||||
/* output: actual total log contents size (including terminating zero).
|
||||
/* output: actual total log contents size (including termintaing zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
__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 token_fd
|
||||
|
||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
@@ -132,7 +129,7 @@ struct bpf_btf_load_opts {
|
||||
char *log_buf;
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
/* output: actual total log contents size (including terminating zero).
|
||||
/* output: actual total log contents size (including termintaing zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
* If kernel doesn't support this feature, log_size is left unchanged.
|
||||
@@ -487,10 +484,9 @@ 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
|
||||
#define bpf_get_fd_by_id_opts__last_field open_flags
|
||||
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
|
||||
|
||||
@@ -388,13 +388,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)
|
||||
|
||||
@@ -34,7 +34,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;
|
||||
|
||||
@@ -44,14 +44,6 @@ struct bpf_dynptr;
|
||||
struct iphdr;
|
||||
struct ipv6hdr;
|
||||
|
||||
#ifndef __bpf_fastcall
|
||||
#if __has_attribute(bpf_fastcall)
|
||||
#define __bpf_fastcall __attribute__((bpf_fastcall))
|
||||
#else
|
||||
#define __bpf_fastcall
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* bpf_map_lookup_elem
|
||||
*
|
||||
@@ -211,21 +203,17 @@ static __u32 (* const bpf_get_prandom_u32)(void) = (void *) 7;
|
||||
* Returns
|
||||
* The SMP id of the processor running the program.
|
||||
*/
|
||||
static __bpf_fastcall __u32 (* const bpf_get_smp_processor_id)(void) = (void *) 8;
|
||||
static __u32 (* const bpf_get_smp_processor_id)(void) = (void *) 8;
|
||||
|
||||
/*
|
||||
* bpf_skb_store_bytes
|
||||
*
|
||||
* Store *len* bytes from address *from* into the packet
|
||||
* associated to *skb*, at *offset*. The *flags* are a combination
|
||||
* of the following values:
|
||||
*
|
||||
* **BPF_F_RECOMPUTE_CSUM**
|
||||
* Automatically update *skb*\ **->csum** after storing the
|
||||
* bytes.
|
||||
* **BPF_F_INVALIDATE_HASH**
|
||||
* Set *skb*\ **->hash**, *skb*\ **->swhash** and *skb*\
|
||||
* **->l4hash** to 0.
|
||||
* associated to *skb*, at *offset*. *flags* are a combination of
|
||||
* **BPF_F_RECOMPUTE_CSUM** (automatically recompute the
|
||||
* checksum for the packet after storing the bytes) and
|
||||
* **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\
|
||||
* **->swhash** and *skb*\ **->l4hash** to 0).
|
||||
*
|
||||
* A call to this helper is susceptible to change the underlying
|
||||
* packet buffer. Therefore, at load time, all checks on pointers
|
||||
@@ -285,7 +273,7 @@ static long (* const bpf_l3_csum_replace)(struct __sk_buff *skb, __u32 offset, _
|
||||
* untouched (unless **BPF_F_MARK_ENFORCE** is added as well), and
|
||||
* for updates resulting in a null checksum the value is set to
|
||||
* **CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates
|
||||
* that the modified header field is part of the pseudo-header.
|
||||
* the checksum is to be computed against a pseudo-header.
|
||||
*
|
||||
* This helper works in combination with **bpf_csum_diff**\ (),
|
||||
* which does not update the checksum in-place, but offers more
|
||||
@@ -1236,7 +1224,7 @@ static long (* const bpf_set_hash)(struct __sk_buff *skb, __u32 hash) = (void *)
|
||||
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
|
||||
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
|
||||
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
|
||||
* **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**.
|
||||
* **TCP_BPF_RTO_MIN**.
|
||||
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
|
||||
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
|
||||
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
|
||||
@@ -1523,6 +1511,10 @@ static long (* const bpf_getsockopt)(void *bpf_socket, int level, int optname, v
|
||||
* option, and in this case it only works on functions tagged with
|
||||
* **ALLOW_ERROR_INJECTION** in the kernel code.
|
||||
*
|
||||
* Also, the helper is only available for the architectures having
|
||||
* the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing,
|
||||
* x86 architecture is the only one to support this feature.
|
||||
*
|
||||
* Returns
|
||||
* 0
|
||||
*/
|
||||
@@ -4228,7 +4220,7 @@ static long (* const bpf_find_vma)(struct task_struct *task, __u64 addr, void *c
|
||||
* Currently, the **flags** must be 0. Currently, nr_loops is
|
||||
* limited to 1 << 23 (~8 million) loops.
|
||||
*
|
||||
* long (\*callback_fn)(u64 index, void \*ctx);
|
||||
* long (\*callback_fn)(u32 index, void \*ctx);
|
||||
*
|
||||
* where **index** is the current index in the loop. The index
|
||||
* is zero-indexed.
|
||||
@@ -4432,10 +4424,9 @@ static long (* const bpf_ima_file_hash)(struct file *file, void *dst, __u32 size
|
||||
/*
|
||||
* bpf_kptr_xchg
|
||||
*
|
||||
* Exchange kptr at pointer *dst* with *ptr*, and return the old value.
|
||||
* *dst* can be map value or local kptr. *ptr* can be NULL, otherwise
|
||||
* it must be a referenced pointer which will be released when this helper
|
||||
* is called.
|
||||
* Exchange kptr at pointer *map_value* with *ptr*, and return the
|
||||
* old value. *ptr* can be NULL, otherwise it must be a referenced
|
||||
* pointer which will be released when this helper is called.
|
||||
*
|
||||
* Returns
|
||||
* The old value of kptr (which can be NULL). The returned pointer
|
||||
@@ -4443,7 +4434,7 @@ static long (* const bpf_ima_file_hash)(struct file *file, void *dst, __u32 size
|
||||
* corresponding release function, or moved into a BPF map before
|
||||
* program exit.
|
||||
*/
|
||||
static void *(* const bpf_kptr_xchg)(void *dst, void *ptr) = (void *) 194;
|
||||
static void *(* const bpf_kptr_xchg)(void *map_value, void *ptr) = (void *) 194;
|
||||
|
||||
/*
|
||||
* bpf_map_lookup_percpu_elem
|
||||
|
||||
@@ -15,14 +15,6 @@
|
||||
#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
|
||||
* different sections in elf_bpf file. Section names
|
||||
@@ -193,7 +185,6 @@ enum libbpf_tristate {
|
||||
#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) ({ \
|
||||
@@ -350,7 +341,7 @@ extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;
|
||||
* 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)
|
||||
* For iterating integers, the difference betwen bpf_for_each(num, i, N, M)
|
||||
* and bpf_for(i, N, M) is in that bpf_for() provides additional proof to
|
||||
* verifier that i is in [N, M) range, and in bpf_for_each() case i is `int
|
||||
* *`, not just `int`. So for integers bpf_for() is more convenient.
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
|
||||
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))
|
||||
@@ -179,7 +179,7 @@ struct pt_regs___s390 {
|
||||
#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_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||
BPF_CORE_READ((const struct pt_regs___s390 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||
|
||||
@@ -222,7 +222,7 @@ struct pt_regs___s390 {
|
||||
|
||||
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))
|
||||
@@ -241,7 +241,7 @@ struct pt_regs___arm64 {
|
||||
#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_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) \
|
||||
BPF_CORE_READ((const struct pt_regs___arm64 *)(x), __PT_PARM1_SYSCALL_REG)
|
||||
|
||||
@@ -351,10 +351,6 @@ struct pt_regs___arm64 {
|
||||
* 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
|
||||
@@ -366,15 +362,12 @@ struct pt_regs___riscv {
|
||||
#define __PT_PARM7_REG a6
|
||||
#define __PT_PARM8_REG a7
|
||||
|
||||
#define __PT_PARM1_SYSCALL_REG orig_a0
|
||||
#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_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
|
||||
@@ -480,7 +473,7 @@ struct pt_regs;
|
||||
#endif
|
||||
/*
|
||||
* Similarly, syscall-specific conventions might differ between function call
|
||||
* conventions within each architecture. All supported architectures pass
|
||||
* conventions within each architecutre. All supported architectures pass
|
||||
* either 6 or 7 syscall arguments in registers.
|
||||
*
|
||||
* See syscall(2) manpage for succinct table with information on each arch.
|
||||
@@ -522,7 +515,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
|
||||
@@ -658,7 +651,7 @@ struct pt_regs;
|
||||
* 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
|
||||
@@ -808,7 +801,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().
|
||||
|
||||
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>
|
||||
|
||||
@@ -21,7 +21,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;
|
||||
@@ -305,7 +304,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.
|
||||
*/
|
||||
@@ -868,8 +867,8 @@ static void btf_dump_emit_bit_padding(const struct btf_dump *d,
|
||||
} 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;
|
||||
int new_off, pad_bits, bits, i;
|
||||
const char *pad_type;
|
||||
|
||||
if (cur_off >= next_off)
|
||||
return; /* no gap */
|
||||
@@ -1305,7 +1304,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 +1493,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 +1559,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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -24,12 +24,10 @@
|
||||
|
||||
int elf_open(const char *binary_path, struct elf_fd *elf_fd)
|
||||
{
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
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;
|
||||
@@ -37,7 +35,8 @@ int elf_open(const char *binary_path, struct elf_fd *elf_fd)
|
||||
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));
|
||||
pr_warn("elf: failed to open %s: %s\n", binary_path,
|
||||
libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
|
||||
return ret;
|
||||
}
|
||||
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
||||
|
||||
@@ -47,6 +47,7 @@ static int probe_kern_prog_name(int token_fd)
|
||||
|
||||
static int probe_kern_global_data(int token_fd)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42),
|
||||
@@ -66,8 +67,9 @@ static int probe_kern_global_data(int token_fd)
|
||||
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));
|
||||
cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
|
||||
pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
|
||||
__func__, cp, -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -265,6 +267,7 @@ static int probe_kern_probe_read_kernel(int token_fd)
|
||||
|
||||
static int probe_prog_bind_map(int token_fd)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
@@ -282,8 +285,9 @@ static int probe_prog_bind_map(int token_fd)
|
||||
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));
|
||||
cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg));
|
||||
pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n",
|
||||
__func__, cp, -ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -600,8 +604,7 @@ bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_
|
||||
} 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));
|
||||
pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret);
|
||||
WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
|
||||
}
|
||||
}
|
||||
|
||||
186
src/gen_loader.c
186
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) {
|
||||
@@ -818,12 +784,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
|
||||
@@ -874,7 +840,7 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 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)));
|
||||
@@ -965,94 +931,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 +1040,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 +1068,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 +1084,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 +1112,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 */
|
||||
|
||||
@@ -166,8 +166,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 +178,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 +190,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 */
|
||||
|
||||
1088
src/libbpf.c
1088
src/libbpf.c
File diff suppressed because it is too large
Load Diff
68
src/libbpf.h
68
src/libbpf.h
@@ -152,7 +152,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
|
||||
@@ -241,19 +241,6 @@ 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
|
||||
@@ -307,14 +294,6 @@ 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 +455,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,
|
||||
@@ -565,12 +544,10 @@ struct bpf_kprobe_multi_opts {
|
||||
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 session
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
||||
@@ -592,12 +569,10 @@ struct bpf_uprobe_multi_opts {
|
||||
size_t cnt;
|
||||
/* create return uprobes */
|
||||
bool retprobe;
|
||||
/* create session kprobes */
|
||||
bool session;
|
||||
size_t :0;
|
||||
};
|
||||
|
||||
#define bpf_uprobe_multi_opts__last_field session
|
||||
#define bpf_uprobe_multi_opts__last_field retprobe
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program
|
||||
@@ -704,7 +679,7 @@ struct bpf_uprobe_opts {
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
@@ -940,12 +915,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 +978,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
|
||||
@@ -1624,11 +1576,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 +1672,6 @@ struct bpf_map_skeleton {
|
||||
const char *name;
|
||||
struct bpf_map **map;
|
||||
void **mmaped;
|
||||
struct bpf_link **link;
|
||||
};
|
||||
|
||||
struct bpf_prog_skeleton {
|
||||
@@ -1817,14 +1768,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);
|
||||
|
||||
|
||||
@@ -419,28 +419,7 @@ LIBBPF_1.4.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;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define __LIBBPF_LIBBPF_INTERNAL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <byteswap.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
@@ -235,9 +234,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)
|
||||
{
|
||||
@@ -409,7 +405,6 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
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);
|
||||
|
||||
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 +445,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 +481,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,59 +508,11 @@ 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,
|
||||
@@ -618,16 +563,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).
|
||||
@@ -667,15 +602,6 @@ 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -97,6 +97,9 @@ __u32 get_kernel_version(void)
|
||||
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
|
||||
return 0;
|
||||
|
||||
if (major == 4 && minor == 19 && patch > 255)
|
||||
return KERNEL_VERSION(major, minor, 255);
|
||||
|
||||
return KERNEL_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
#define __LIBBPF_VERSION_H
|
||||
|
||||
#define LIBBPF_MAJOR_VERSION 1
|
||||
#define LIBBPF_MINOR_VERSION 6
|
||||
#define LIBBPF_MINOR_VERSION 5
|
||||
|
||||
#endif /* __LIBBPF_VERSION_H */
|
||||
|
||||
418
src/linker.c
418
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;
|
||||
}
|
||||
@@ -1087,33 +957,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 +1095,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;
|
||||
@@ -1316,10 +1154,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 +1210,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 +1399,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 +1948,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 +1997,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;
|
||||
}
|
||||
@@ -2223,7 +2057,7 @@ 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;
|
||||
}
|
||||
|
||||
/* shdr->sh_link points to SYMTAB */
|
||||
@@ -2379,17 +2213,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 +2234,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 +2324,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 +2394,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 +2607,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 +2675,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 +2708,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,7 +2726,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -2928,7 +2738,7 @@ static int finalize_btf(struct bpf_linker *linker)
|
||||
|
||||
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 +2914,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;
|
||||
}
|
||||
|
||||
|
||||
15
src/nlattr.c
15
src/nlattr.c
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -683,7 +683,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
|
||||
{
|
||||
const struct bpf_core_accessor *acc;
|
||||
const struct btf_type *t;
|
||||
__u32 byte_off, byte_sz, bit_off, bit_sz, field_type_id, elem_id;
|
||||
__u32 byte_off, byte_sz, bit_off, bit_sz, field_type_id;
|
||||
const struct btf_member *m;
|
||||
const struct btf_type *mt;
|
||||
bool bitfield;
|
||||
@@ -706,14 +706,8 @@ static int bpf_core_calc_field_relo(const char *prog_name,
|
||||
if (!acc->name) {
|
||||
if (relo->kind == BPF_CORE_FIELD_BYTE_OFFSET) {
|
||||
*val = spec->bit_offset / 8;
|
||||
/* remember field size for load/store mem size;
|
||||
* note, for arrays we care about individual element
|
||||
* sizes, not the overall array size
|
||||
*/
|
||||
t = skip_mods_and_typedefs(spec->btf, acc->type_id, &elem_id);
|
||||
while (btf_is_array(t))
|
||||
t = skip_mods_and_typedefs(spec->btf, btf_array(t)->type, &elem_id);
|
||||
sz = btf__resolve_size(spec->btf, elem_id);
|
||||
/* remember field size for load/store mem size */
|
||||
sz = btf__resolve_size(spec->btf, acc->type_id);
|
||||
if (sz < 0)
|
||||
return -EINVAL;
|
||||
*field_sz = sz;
|
||||
@@ -773,17 +767,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
|
||||
case BPF_CORE_FIELD_BYTE_OFFSET:
|
||||
*val = byte_off;
|
||||
if (!bitfield) {
|
||||
/* remember field size for load/store mem size;
|
||||
* note, for arrays we care about individual element
|
||||
* sizes, not the overall array size
|
||||
*/
|
||||
t = skip_mods_and_typedefs(spec->btf, field_type_id, &elem_id);
|
||||
while (btf_is_array(t))
|
||||
t = skip_mods_and_typedefs(spec->btf, btf_array(t)->type, &elem_id);
|
||||
sz = btf__resolve_size(spec->btf, elem_id);
|
||||
if (sz < 0)
|
||||
return -EINVAL;
|
||||
*field_sz = sz;
|
||||
*field_sz = byte_sz;
|
||||
*type_id = field_type_id;
|
||||
}
|
||||
break;
|
||||
@@ -1355,7 +1339,7 @@ int bpf_core_calc_relo_insn(const char *prog_name,
|
||||
cands->cands[i].id, cand_spec);
|
||||
if (err < 0) {
|
||||
bpf_core_format_spec(spec_buf, sizeof(spec_buf), cand_spec);
|
||||
pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n",
|
||||
pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n ",
|
||||
prog_name, relo_idx, i, spec_buf, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "bpf.h"
|
||||
#include "str_error.h"
|
||||
|
||||
struct ring {
|
||||
ring_buffer_sample_fn sample_cb;
|
||||
@@ -89,8 +88,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
err = bpf_map_get_info_by_fd(map_fd, &info, &len);
|
||||
if (err) {
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to get map info for fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
@@ -124,8 +123,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
|
||||
if (tmp == MAP_FAILED) {
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
}
|
||||
r->consumer_pos = tmp;
|
||||
@@ -143,8 +142,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ, MAP_SHARED, map_fd, rb->page_size);
|
||||
if (tmp == MAP_FAILED) {
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
}
|
||||
r->producer_pos = tmp;
|
||||
@@ -157,8 +156,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
e->data.fd = rb->ring_cnt;
|
||||
if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, e) < 0) {
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to epoll add map fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@@ -206,7 +205,7 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,
|
||||
rb->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (rb->epoll_fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to create epoll instance: %s\n", errstr(err));
|
||||
pr_warn("ringbuf: failed to create epoll instance: %d\n", err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@@ -459,8 +458,7 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
|
||||
err = bpf_map_get_info_by_fd(map_fd, &info, &len);
|
||||
if (err) {
|
||||
err = -errno;
|
||||
pr_warn("user ringbuf: failed to get map info for fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("user ringbuf: failed to get map info for fd=%d: %d\n", map_fd, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -476,8 +474,8 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
|
||||
tmp = mmap(NULL, rb->page_size, PROT_READ, MAP_SHARED, map_fd, 0);
|
||||
if (tmp == MAP_FAILED) {
|
||||
err = -errno;
|
||||
pr_warn("user ringbuf: failed to mmap consumer page for map fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("user ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return err;
|
||||
}
|
||||
rb->consumer_pos = tmp;
|
||||
@@ -496,8 +494,8 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
|
||||
map_fd, rb->page_size);
|
||||
if (tmp == MAP_FAILED) {
|
||||
err = -errno;
|
||||
pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %s\n",
|
||||
map_fd, errstr(err));
|
||||
pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -508,7 +506,7 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd)
|
||||
rb_epoll->events = EPOLLOUT;
|
||||
if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, rb_epoll) < 0) {
|
||||
err = -errno;
|
||||
pr_warn("user ringbuf: failed to epoll add map fd=%d: %s\n", map_fd, errstr(err));
|
||||
pr_warn("user ringbuf: failed to epoll add map fd=%d: %d\n", map_fd, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -533,7 +531,7 @@ user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts)
|
||||
rb->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (rb->epoll_fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("user ringbuf: failed to create epoll instance: %s\n", errstr(err));
|
||||
pr_warn("user ringbuf: failed to create epoll instance: %d\n", err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ static inline void skel_free(const void *p)
|
||||
* The loader program will perform probe_read_kernel() from maps.rodata.initial_value.
|
||||
* skel_finalize_map_data() sets skel->rodata to point to actual value in a bpf map and
|
||||
* does maps.rodata.initial_value = ~0ULL to signal skel_free_map_data() that kvfree
|
||||
* is not necessary.
|
||||
* is not nessary.
|
||||
*
|
||||
* For user space:
|
||||
* skel_prep_map_data() mmaps anon memory into skel->rodata that can be accessed directly.
|
||||
@@ -351,11 +351,10 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
||||
attr.test.ctx_size_in = opts->ctx->sz;
|
||||
err = skel_sys_bpf(BPF_PROG_RUN, &attr, test_run_attr_sz);
|
||||
if (err < 0 || (int)attr.test.retval < 0) {
|
||||
opts->errstr = "failed to execute loader prog";
|
||||
if (err < 0) {
|
||||
opts->errstr = "failed to execute loader prog";
|
||||
set_err;
|
||||
} else {
|
||||
opts->errstr = "error returned by loader prog";
|
||||
err = (int)attr.test.retval;
|
||||
#ifndef __KERNEL__
|
||||
errno = -err;
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include <errno.h>
|
||||
#include "str_error.h"
|
||||
|
||||
#ifndef ENOTSUPP
|
||||
#define ENOTSUPP 524
|
||||
#endif
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
@@ -35,70 +31,3 @@ char *libbpf_strerror_r(int err, char *dst, int len)
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
const char *libbpf_errstr(int err)
|
||||
{
|
||||
static __thread char buf[12];
|
||||
|
||||
if (err > 0)
|
||||
err = -err;
|
||||
|
||||
switch (err) {
|
||||
case -E2BIG: return "-E2BIG";
|
||||
case -EACCES: return "-EACCES";
|
||||
case -EADDRINUSE: return "-EADDRINUSE";
|
||||
case -EADDRNOTAVAIL: return "-EADDRNOTAVAIL";
|
||||
case -EAGAIN: return "-EAGAIN";
|
||||
case -EALREADY: return "-EALREADY";
|
||||
case -EBADF: return "-EBADF";
|
||||
case -EBADFD: return "-EBADFD";
|
||||
case -EBUSY: return "-EBUSY";
|
||||
case -ECANCELED: return "-ECANCELED";
|
||||
case -ECHILD: return "-ECHILD";
|
||||
case -EDEADLK: return "-EDEADLK";
|
||||
case -EDOM: return "-EDOM";
|
||||
case -EEXIST: return "-EEXIST";
|
||||
case -EFAULT: return "-EFAULT";
|
||||
case -EFBIG: return "-EFBIG";
|
||||
case -EILSEQ: return "-EILSEQ";
|
||||
case -EINPROGRESS: return "-EINPROGRESS";
|
||||
case -EINTR: return "-EINTR";
|
||||
case -EINVAL: return "-EINVAL";
|
||||
case -EIO: return "-EIO";
|
||||
case -EISDIR: return "-EISDIR";
|
||||
case -ELOOP: return "-ELOOP";
|
||||
case -EMFILE: return "-EMFILE";
|
||||
case -EMLINK: return "-EMLINK";
|
||||
case -EMSGSIZE: return "-EMSGSIZE";
|
||||
case -ENAMETOOLONG: return "-ENAMETOOLONG";
|
||||
case -ENFILE: return "-ENFILE";
|
||||
case -ENODATA: return "-ENODATA";
|
||||
case -ENODEV: return "-ENODEV";
|
||||
case -ENOENT: return "-ENOENT";
|
||||
case -ENOEXEC: return "-ENOEXEC";
|
||||
case -ENOLINK: return "-ENOLINK";
|
||||
case -ENOMEM: return "-ENOMEM";
|
||||
case -ENOSPC: return "-ENOSPC";
|
||||
case -ENOTBLK: return "-ENOTBLK";
|
||||
case -ENOTDIR: return "-ENOTDIR";
|
||||
case -ENOTSUPP: return "-ENOTSUPP";
|
||||
case -ENOTTY: return "-ENOTTY";
|
||||
case -ENXIO: return "-ENXIO";
|
||||
case -EOPNOTSUPP: return "-EOPNOTSUPP";
|
||||
case -EOVERFLOW: return "-EOVERFLOW";
|
||||
case -EPERM: return "-EPERM";
|
||||
case -EPIPE: return "-EPIPE";
|
||||
case -EPROTO: return "-EPROTO";
|
||||
case -EPROTONOSUPPORT: return "-EPROTONOSUPPORT";
|
||||
case -ERANGE: return "-ERANGE";
|
||||
case -EROFS: return "-EROFS";
|
||||
case -ESPIPE: return "-ESPIPE";
|
||||
case -ESRCH: return "-ESRCH";
|
||||
case -ETXTBSY: return "-ETXTBSY";
|
||||
case -EUCLEAN: return "-EUCLEAN";
|
||||
case -EXDEV: return "-EXDEV";
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "%d", err);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,4 @@
|
||||
|
||||
char *libbpf_strerror_r(int err, char *dst, int len);
|
||||
|
||||
/**
|
||||
* @brief **libbpf_errstr()** returns string corresponding to numeric errno
|
||||
* @param err negative numeric errno
|
||||
* @return pointer to string representation of the errno, that is invalidated
|
||||
* upon the next call.
|
||||
*/
|
||||
const char *libbpf_errstr(int err);
|
||||
|
||||
#define errstr(err) libbpf_errstr(err)
|
||||
|
||||
#endif /* __LIBBPF_STR_ERROR_H */
|
||||
|
||||
@@ -39,7 +39,7 @@ enum __bpf_usdt_arg_type {
|
||||
struct __bpf_usdt_arg_spec {
|
||||
/* u64 scalar interpreted depending on arg_type, see below */
|
||||
__u64 val_off;
|
||||
/* arg location case, see bpf_usdt_arg() for details */
|
||||
/* arg location case, see bpf_udst_arg() for details */
|
||||
enum __bpf_usdt_arg_type arg_type;
|
||||
/* offset of referenced register within struct pt_regs */
|
||||
short reg_off;
|
||||
@@ -108,38 +108,6 @@ int bpf_usdt_arg_cnt(struct pt_regs *ctx)
|
||||
return spec->arg_cnt;
|
||||
}
|
||||
|
||||
/* Returns the size in bytes of the #*arg_num* (zero-indexed) USDT argument.
|
||||
* Returns negative error if argument is not found or arg_num is invalid.
|
||||
*/
|
||||
static __always_inline
|
||||
int bpf_usdt_arg_size(struct pt_regs *ctx, __u64 arg_num)
|
||||
{
|
||||
struct __bpf_usdt_arg_spec *arg_spec;
|
||||
struct __bpf_usdt_spec *spec;
|
||||
int spec_id;
|
||||
|
||||
spec_id = __bpf_usdt_spec_id(ctx);
|
||||
if (spec_id < 0)
|
||||
return -ESRCH;
|
||||
|
||||
spec = bpf_map_lookup_elem(&__bpf_usdt_specs, &spec_id);
|
||||
if (!spec)
|
||||
return -ESRCH;
|
||||
|
||||
if (arg_num >= BPF_USDT_MAX_ARG_CNT)
|
||||
return -ENOENT;
|
||||
barrier_var(arg_num);
|
||||
if (arg_num >= spec->arg_cnt)
|
||||
return -ENOENT;
|
||||
|
||||
arg_spec = &spec->args[arg_num];
|
||||
|
||||
/* arg_spec->arg_bitshift = 64 - arg_sz * 8
|
||||
* so: arg_sz = (64 - arg_spec->arg_bitshift) / 8
|
||||
*/
|
||||
return (unsigned int)(64 - arg_spec->arg_bitshift) / 8;
|
||||
}
|
||||
|
||||
/* Fetch USDT argument #*arg_num* (zero-indexed) and put its value into *res.
|
||||
* Returns 0 on success; negative error, otherwise.
|
||||
* On error *res is guaranteed to be set to zero.
|
||||
|
||||
34
src/usdt.c
34
src/usdt.c
@@ -20,7 +20,6 @@
|
||||
#include "libbpf_common.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "hashmap.h"
|
||||
#include "str_error.h"
|
||||
|
||||
/* libbpf's USDT support consists of BPF-side state/code and user-space
|
||||
* state/code working together in concert. BPF-side parts are defined in
|
||||
@@ -466,8 +465,8 @@ static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs,
|
||||
goto proceed;
|
||||
|
||||
if (!realpath(lib_path, path)) {
|
||||
pr_warn("usdt: failed to get absolute path of '%s' (err %s), using path as is...\n",
|
||||
lib_path, errstr(-errno));
|
||||
pr_warn("usdt: failed to get absolute path of '%s' (err %d), using path as is...\n",
|
||||
lib_path, -errno);
|
||||
libbpf_strlcpy(path, lib_path, sizeof(path));
|
||||
}
|
||||
|
||||
@@ -476,8 +475,8 @@ proceed:
|
||||
f = fopen(line, "re");
|
||||
if (!f) {
|
||||
err = -errno;
|
||||
pr_warn("usdt: failed to open '%s' to get base addr of '%s': %s\n",
|
||||
line, lib_path, errstr(err));
|
||||
pr_warn("usdt: failed to open '%s' to get base addr of '%s': %d\n",
|
||||
line, lib_path, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -607,8 +606,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
|
||||
|
||||
err = parse_elf_segs(elf, path, &segs, &seg_cnt);
|
||||
if (err) {
|
||||
pr_warn("usdt: failed to process ELF program segments for '%s': %s\n",
|
||||
path, errstr(err));
|
||||
pr_warn("usdt: failed to process ELF program segments for '%s': %d\n", path, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@@ -661,7 +659,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
|
||||
* [0] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
|
||||
*/
|
||||
usdt_abs_ip = note.loc_addr;
|
||||
if (base_addr && note.base_addr)
|
||||
if (base_addr)
|
||||
usdt_abs_ip += base_addr - note.base_addr;
|
||||
|
||||
/* When attaching uprobes (which is what USDTs basically are)
|
||||
@@ -710,8 +708,8 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
|
||||
if (vma_seg_cnt == 0) {
|
||||
err = parse_vma_segs(pid, path, &vma_segs, &vma_seg_cnt);
|
||||
if (err) {
|
||||
pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %s\n",
|
||||
pid, path, errstr(err));
|
||||
pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %d\n",
|
||||
pid, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
@@ -1049,8 +1047,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
|
||||
if (is_new && bpf_map_update_elem(spec_map_fd, &spec_id, &target->spec, BPF_ANY)) {
|
||||
err = -errno;
|
||||
pr_warn("usdt: failed to set USDT spec #%d for '%s:%s' in '%s': %s\n",
|
||||
spec_id, usdt_provider, usdt_name, path, errstr(err));
|
||||
pr_warn("usdt: failed to set USDT spec #%d for '%s:%s' in '%s': %d\n",
|
||||
spec_id, usdt_provider, usdt_name, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
if (!man->has_bpf_cookie &&
|
||||
@@ -1060,9 +1058,9 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
pr_warn("usdt: IP collision detected for spec #%d for '%s:%s' in '%s'\n",
|
||||
spec_id, usdt_provider, usdt_name, path);
|
||||
} else {
|
||||
pr_warn("usdt: failed to map IP 0x%lx to spec #%d for '%s:%s' in '%s': %s\n",
|
||||
pr_warn("usdt: failed to map IP 0x%lx to spec #%d for '%s:%s' in '%s': %d\n",
|
||||
target->abs_ip, spec_id, usdt_provider, usdt_name,
|
||||
path, errstr(err));
|
||||
path, err);
|
||||
}
|
||||
goto err_out;
|
||||
}
|
||||
@@ -1078,8 +1076,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
target->rel_ip, &opts);
|
||||
err = libbpf_get_error(uprobe_link);
|
||||
if (err) {
|
||||
pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %s\n",
|
||||
i, usdt_provider, usdt_name, path, errstr(err));
|
||||
pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n",
|
||||
i, usdt_provider, usdt_name, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@@ -1101,8 +1099,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
|
||||
NULL, &opts_multi);
|
||||
if (!link->multi_link) {
|
||||
err = -errno;
|
||||
pr_warn("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %s\n",
|
||||
usdt_provider, usdt_name, path, errstr(err));
|
||||
pr_warn("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %d\n",
|
||||
usdt_provider, usdt_name, path, err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user