mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-14 13:29:06 +08:00
Compare commits
3 Commits
v0.8.0_net
...
netdata-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
673424c561 | ||
|
|
d2feaff998 | ||
|
|
0d4b75d30e |
30
.github/actions/build-selftests/action.yml
vendored
30
.github/actions/build-selftests/action.yml
vendored
@@ -1,30 +0,0 @@
|
||||
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: |
|
||||
echo "::group::Setup Env"
|
||||
sudo apt-get install -y qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev python3-docutils
|
||||
echo "::endgroup::"
|
||||
- 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
|
||||
44
.github/actions/build-selftests/helpers.sh
vendored
44
.github/actions/build-selftests/helpers.sh
vendored
@@ -1,44 +0,0 @@
|
||||
# $1 - start or end
|
||||
# $2 - fold identifier, no spaces
|
||||
# $3 - fold section description
|
||||
travis_fold() {
|
||||
local YELLOW='\033[1;33m'
|
||||
local NOCOLOR='\033[0m'
|
||||
if [ -z ${GITHUB_WORKFLOW+x} ]; then
|
||||
echo travis_fold:$1:$2
|
||||
if [ ! -z "${3:-}" ]; then
|
||||
echo -e "${YELLOW}$3${NOCOLOR}"
|
||||
fi
|
||||
echo
|
||||
else
|
||||
if [ $1 = "start" ]; then
|
||||
line="::group::$2"
|
||||
if [ ! -z "${3:-}" ]; then
|
||||
line="$line - ${YELLOW}$3${NOCOLOR}"
|
||||
fi
|
||||
else
|
||||
line="::endgroup::"
|
||||
fi
|
||||
echo -e "$line"
|
||||
fi
|
||||
}
|
||||
|
||||
__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
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
|
||||
89024
.github/actions/build-selftests/vmlinux.h
vendored
89024
.github/actions/build-selftests/vmlinux.h
vendored
File diff suppressed because it is too large
Load Diff
16
.github/actions/debian/action.yml
vendored
16
.github/actions/debian/action.yml
vendored
@@ -1,16 +0,0 @@
|
||||
name: 'debian'
|
||||
description: 'Build'
|
||||
inputs:
|
||||
target:
|
||||
description: 'Run target'
|
||||
required: true
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
source /tmp/ci_setup
|
||||
bash -x $CI_ROOT/managers/debian.sh SETUP
|
||||
bash -x $CI_ROOT/managers/debian.sh ${{ inputs.target }}
|
||||
bash -x $CI_ROOT/managers/debian.sh CLEANUP
|
||||
shell: bash
|
||||
|
||||
23
.github/actions/setup/action.yml
vendored
23
.github/actions/setup/action.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: 'setup'
|
||||
description: 'setup env, create /tmp/ci_setup'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- id: variables
|
||||
run: |
|
||||
export REPO_ROOT=$GITHUB_WORKSPACE
|
||||
export CI_ROOT=$REPO_ROOT/travis-ci
|
||||
# this is somewhat ugly, but that is the easiest way to share this code with
|
||||
# arch specific docker
|
||||
echo 'echo ::group::Env setup' > /tmp/ci_setup
|
||||
echo export DEBIAN_FRONTEND=noninteractive >> /tmp/ci_setup
|
||||
echo sudo apt-get update >> /tmp/ci_setup
|
||||
echo sudo apt-get install -y aptitude qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev libguestfs-tools >> /tmp/ci_setup
|
||||
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
||||
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
||||
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
||||
echo export CI_ROOT=$REPO_ROOT/travis-ci >> /tmp/ci_setup
|
||||
echo export VMTEST_ROOT=$CI_ROOT/vmtest >> /tmp/ci_setup
|
||||
echo 'echo ::endgroup::' >> /tmp/ci_setup
|
||||
shell: bash
|
||||
|
||||
87
.github/actions/vmtest/action.yml
vendored
87
.github/actions/vmtest/action.yml
vendored
@@ -1,87 +0,0 @@
|
||||
name: 'vmtest'
|
||||
description: 'Build + run vmtest'
|
||||
inputs:
|
||||
kernel:
|
||||
description: 'kernel version or LATEST'
|
||||
required: true
|
||||
default: 'LATEST'
|
||||
arch:
|
||||
description: 'what arch to test'
|
||||
required: true
|
||||
default: 'x86_64'
|
||||
pahole:
|
||||
description: 'pahole rev or master'
|
||||
required: true
|
||||
default: 'master'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# setup envinronment
|
||||
- name: Setup environment
|
||||
uses: libbpf/ci/setup-build-env@master
|
||||
with:
|
||||
pahole: ${{ inputs.pahole }}
|
||||
# 1. download CHECKPOINT kernel source
|
||||
- name: Get checkpoint commit
|
||||
shell: bash
|
||||
run: |
|
||||
cat CHECKPOINT-COMMIT
|
||||
echo "CHECKPOINT=$(cat CHECKPOINT-COMMIT)" >> $GITHUB_ENV
|
||||
- name: Get kernel source at checkpoint
|
||||
uses: libbpf/ci/get-linux-source@master
|
||||
with:
|
||||
repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||
rev: ${{ env.CHECKPOINT }}
|
||||
dest: '${{ github.workspace }}/.kernel'
|
||||
- name: Patch kernel source
|
||||
uses: libbpf/ci/patch-kernel@master
|
||||
with:
|
||||
patches-root: '${{ github.workspace }}/travis-ci/diffs'
|
||||
repo-root: '.kernel'
|
||||
- name: Prepare to build BPF selftests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::Prepare buidling selftest"
|
||||
cd .kernel
|
||||
cp ${{ github.workspace }}/travis-ci/vmtest/configs/config-latest.${{ inputs.arch }} .config
|
||||
make olddefconfig && make prepare
|
||||
cd -
|
||||
echo "::endgroup::"
|
||||
# 2. if kernel == LATEST, build kernel image from tree
|
||||
- name: Build kernel image
|
||||
if: ${{ inputs.kernel == 'LATEST' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::Build Kernel Image"
|
||||
cd .kernel
|
||||
make -j $((4*$(nproc))) all > /dev/null
|
||||
cp vmlinux ${{ github.workspace }}
|
||||
cd -
|
||||
echo "::endgroup::"
|
||||
# else, just download prebuilt kernel image
|
||||
- name: Download prebuilt kernel
|
||||
if: ${{ inputs.kernel != 'LATEST' }}
|
||||
uses: libbpf/ci/download-vmlinux@master
|
||||
with:
|
||||
kernel: ${{ inputs.kernel }}
|
||||
arch: ${{ inputs.arch }}
|
||||
# 3. build selftests
|
||||
- name: Build BPF selftests
|
||||
uses: ./.github/actions/build-selftests
|
||||
with:
|
||||
repo-path: '.kernel'
|
||||
kernel: ${{ inputs.kernel }}
|
||||
# 4. prepare rootfs
|
||||
- name: prepare rootfs
|
||||
uses: libbpf/ci/prepare-rootfs@master
|
||||
with:
|
||||
kernel: ${{ inputs.kernel }}
|
||||
project-name: 'libbpf'
|
||||
arch: ${{ inputs.arch }}
|
||||
# 5. run selftest in QEMU
|
||||
- name: Run selftests
|
||||
uses: libbpf/ci/run-qemu@master
|
||||
with:
|
||||
img: '/tmp/root.img'
|
||||
vmlinuz: 'vmlinuz'
|
||||
arch: ${{ inputs.arch }}
|
||||
81
.github/workflows/build.yml
vendored
81
.github/workflows/build.yml
vendored
@@ -1,81 +0,0 @@
|
||||
name: libbpf-build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
concurrency:
|
||||
group: ci-build-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
debian:
|
||||
runs-on: ubuntu-latest
|
||||
name: Debian Build (${{ matrix.name }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: default
|
||||
target: RUN
|
||||
- name: ASan+UBSan
|
||||
target: RUN_ASAN
|
||||
- name: clang
|
||||
target: RUN_CLANG
|
||||
- name: clang ASan+UBSan
|
||||
target: RUN_CLANG_ASAN
|
||||
- name: gcc-10
|
||||
target: RUN_GCC10
|
||||
- name: gcc-10 ASan+UBSan
|
||||
target: RUN_GCC10_ASAN
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
- uses: ./.github/actions/debian
|
||||
name: Build
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
name: Ubuntu Focal Build (${{ matrix.arch }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: aarch64
|
||||
- arch: ppc64le
|
||||
- arch: s390x
|
||||
- arch: x86
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Pre-Setup
|
||||
- run: source /tmp/ci_setup && sudo -E $CI_ROOT/managers/ubuntu.sh
|
||||
if: matrix.arch == 'x86'
|
||||
name: Setup
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Build in docker
|
||||
if: matrix.arch != 'x86'
|
||||
with:
|
||||
distro:
|
||||
ubuntu20.04
|
||||
arch:
|
||||
${{ matrix.arch }}
|
||||
setup:
|
||||
cp /tmp/ci_setup $GITHUB_WORKSPACE
|
||||
dockerRunArgs: |
|
||||
--volume "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export TZ="America/Los_Angeles"
|
||||
apt-get update -y
|
||||
apt-get install -y tzdata build-essential sudo
|
||||
run: source ${GITHUB_WORKSPACE}/ci_setup && $CI_ROOT/managers/ubuntu.sh
|
||||
40
.github/workflows/cifuzz.yml
vendored
40
.github/workflows/cifuzz.yml
vendored
@@ -1,40 +0,0 @@
|
||||
---
|
||||
# https://google.github.io/oss-fuzz/getting-started/continuous-integration/
|
||||
name: CIFuzz
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sanitizer: [address, undefined, memory]
|
||||
steps:
|
||||
- name: Build Fuzzers (${{ matrix.sanitizer }})
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libbpf'
|
||||
dry-run: false
|
||||
allowed-broken-targets-percentage: 0
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Run Fuzzers (${{ matrix.sanitizer }})
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libbpf'
|
||||
fuzz-seconds: 300
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
path: ./out/artifacts
|
||||
31
.github/workflows/coverity.yml
vendored
31
.github/workflows/coverity.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: libbpf-ci-coverity
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
name: Coverity
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/setup
|
||||
- name: Run coverity
|
||||
run: |
|
||||
echo ::group::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}
|
||||
echo ::endgroup::
|
||||
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'
|
||||
- name: SCM log
|
||||
run: cat /home/runner/work/libbpf/libbpf/src/cov-int/scm_log.txt
|
||||
36
.github/workflows/ondemand.yml
vendored
36
.github/workflows/ondemand.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: ondemand
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
kernel-origin:
|
||||
description: 'git repo for linux kernel'
|
||||
default: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||
required: true
|
||||
kernel-rev:
|
||||
description: 'rev/tag/branch for linux kernel'
|
||||
default: "master"
|
||||
required: true
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
name: vmtest with customized pahole/Kernel
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
20
.github/workflows/pahole.yml
vendored
@@ -1,20 +0,0 @@
|
||||
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@v2
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
with:
|
||||
kernel: LATEST
|
||||
pahole: $STAGING
|
||||
42
.github/workflows/test.yml
vendored
42
.github/workflows/test.yml
vendored
@@ -1,42 +0,0 @@
|
||||
name: libbpf-ci
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 18 * * *'
|
||||
|
||||
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-latest
|
||||
arch: 'x86_64'
|
||||
- kernel: '5.5.0'
|
||||
runs_on: ubuntu-latest
|
||||
arch: 'x86_64'
|
||||
- kernel: '4.9.0'
|
||||
runs_on: ubuntu-latest
|
||||
arch: 'x86_64'
|
||||
- kernel: 'LATEST'
|
||||
runs_on: z15
|
||||
arch: 's390x'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
- uses: ./.github/actions/setup
|
||||
name: Setup
|
||||
- uses: ./.github/actions/vmtest
|
||||
name: vmtest
|
||||
with:
|
||||
kernel: ${{ matrix.kernel }}
|
||||
arch: ${{ matrix.arch }}
|
||||
@@ -1,22 +0,0 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
builder: html
|
||||
configuration: docs/conf.py
|
||||
|
||||
formats:
|
||||
- htmlzip
|
||||
- pdf
|
||||
- epub
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
version: 3.7
|
||||
install:
|
||||
- requirements: docs/sphinx/requirements.txt
|
||||
51
.travis.yml
51
.travis.yml
@@ -1,6 +1,6 @@
|
||||
sudo: required
|
||||
language: bash
|
||||
dist: focal
|
||||
dist: bionic
|
||||
services:
|
||||
- docker
|
||||
|
||||
@@ -35,23 +35,8 @@ stages:
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: Builds & Tests
|
||||
name: Kernel 5.5.0 + selftests
|
||||
language: bash
|
||||
env: KERNEL=5.5.0
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||
|
||||
- name: Kernel LATEST + selftests
|
||||
language: bash
|
||||
env: KERNEL=LATEST
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||
|
||||
- name: Kernel 4.9.0 + selftests
|
||||
language: bash
|
||||
env: KERNEL=4.9.0
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||
|
||||
- name: Debian Build
|
||||
- stage: Build & Test
|
||||
name: Debian Build
|
||||
language: bash
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN || travis_terminate 1
|
||||
@@ -75,37 +60,47 @@ jobs:
|
||||
script: $CI_ROOT/managers/debian.sh RUN_CLANG_ASAN || travis_terminate 1
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Build (gcc-10)
|
||||
- name: Debian Build (gcc-8)
|
||||
language: bash
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC10 || travis_terminate 1
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8 || travis_terminate 1
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Build (gcc-10 ASan+UBSan)
|
||||
- name: Debian Build (gcc-8 ASan+UBSan)
|
||||
language: bash
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC10_ASAN || travis_terminate 1
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8_ASAN || travis_terminate 1
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Ubuntu Focal Build
|
||||
- name: Ubuntu Bionic Build
|
||||
language: bash
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||
|
||||
- name: Ubuntu Focal Build (arm)
|
||||
- name: Ubuntu Bionic Build (arm)
|
||||
arch: arm64
|
||||
language: bash
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||
|
||||
- name: Ubuntu Focal Build (s390x)
|
||||
- name: Ubuntu Bionic Build (s390x)
|
||||
arch: s390x
|
||||
language: bash
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||
|
||||
- name: Ubuntu Focal Build (ppc64le)
|
||||
- name: Ubuntu Bionic Build (ppc64le)
|
||||
arch: ppc64le
|
||||
language: bash
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||
|
||||
- name: Kernel 5.5.0 + selftests
|
||||
language: bash
|
||||
env: KERNEL=5.5.0
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||
|
||||
- name: Kernel LATEST + selftests
|
||||
language: bash
|
||||
env: KERNEL=LATEST
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||
|
||||
- stage: Coverity
|
||||
language: bash
|
||||
env:
|
||||
@@ -120,11 +115,9 @@ jobs:
|
||||
- COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd src/"
|
||||
- COVERITY_SCAN_BUILD_COMMAND="make"
|
||||
install:
|
||||
- sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' >>/etc/apt/sources.list
|
||||
- sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' >>/etc/apt/sources.list
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y build-dep libelf-dev
|
||||
- sudo apt-get install -y libelf-dev pkg-config
|
||||
script:
|
||||
- scripts/coverity.sh || travis_terminate 1
|
||||
allow_failures:
|
||||
- env: KERNEL=x.x.x
|
||||
|
||||
@@ -1 +1 @@
|
||||
f3f19f939c11925dadd3f4776f99f8c278a7017b
|
||||
4e15507fea70c0c312d79610efa46b6853ccf8e0
|
||||
|
||||
@@ -1 +1 @@
|
||||
ac6a65868a5a45db49d5ee8524df3b701110d844
|
||||
69119673bd50b176ded34032fadd41530fb5af21
|
||||
|
||||
@@ -7,7 +7,7 @@ Usage-Guide:
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
License-Text:
|
||||
|
||||
Copyright (c) 2015 The Libbpf Authors. All rights reserved.
|
||||
Copyright (c) <year> <owner> . All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
120
README.md
120
README.md
@@ -1,54 +1,32 @@
|
||||
This is a mirror of [bpf-next Linux source
|
||||
tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next)'s
|
||||
|
||||
This is a mirror of [bpf-next linux tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next)'s
|
||||
`tools/lib/bpf` directory plus its supporting header files.
|
||||
|
||||
All the gory details of syncing can be found in `scripts/sync-kernel.sh`
|
||||
script.
|
||||
The following files will by sync'ed with bpf-next repo:
|
||||
- `src/` <-> `bpf-next/tools/lib/bpf/`
|
||||
- `include/uapi/linux/bpf_common.h` <-> `bpf-next/tools/include/uapi/linux/bpf_common.h`
|
||||
- `include/uapi/linux/bpf.h` <-> `bpf-next/tools/include/uapi/linux/bpf.h`
|
||||
- `include/uapi/linux/btf.h` <-> `bpf-next/tools/include/uapi/linux/btf.h`
|
||||
- `include/uapi/linux/if_link.h` <-> `bpf-next/tools/include/uapi/linux/if_link.h`
|
||||
- `include/uapi/linux/if_xdp.h` <-> `bpf-next/tools/include/uapi/linux/if_xdp.h`
|
||||
- `include/uapi/linux/netlink.h` <-> `bpf-next/tools/include/uapi/linux/netlink.h`
|
||||
- `include/tools/libc_compat.h` <-> `bpf-next/tools/include/tools/libc_compat.h`
|
||||
|
||||
Some header files in this repo (`include/linux/*.h`) are reduced versions of
|
||||
their counterpart files at
|
||||
[bpf-next](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/)'s
|
||||
`tools/include/linux/*.h` to make compilation successful.
|
||||
|
||||
BPF/libbpf usage and questions
|
||||
==============================
|
||||
|
||||
Please check out [libbpf-bootstrap](https://github.com/libbpf/libbpf-bootstrap)
|
||||
and [the companion blog post](https://nakryiko.com/posts/libbpf-bootstrap/) for
|
||||
the examples of building BPF applications with libbpf.
|
||||
[libbpf-tools](https://github.com/iovisor/bcc/tree/master/libbpf-tools) are also
|
||||
a good source of the real-world libbpf-based tracing tools.
|
||||
|
||||
See also ["BPF CO-RE reference guide"](https://nakryiko.com/posts/bpf-core-reference-guide/)
|
||||
for the coverage of practical aspects of building BPF CO-RE applications and
|
||||
["BPF CO-RE"](https://nakryiko.com/posts/bpf-portability-and-co-re/) for
|
||||
general introduction into BPF portability issues and BPF CO-RE origins.
|
||||
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
||||
their application, should be sent to bpf@vger.kernel.org mailing list. You can
|
||||
subscribe to it [here](http://vger.kernel.org/vger-lists.html#bpf) and search
|
||||
its archive [here](https://lore.kernel.org/bpf/). Please search the archive
|
||||
before asking new questions. It very well might be that this was already
|
||||
addressed or answered before.
|
||||
|
||||
bpf@vger.kernel.org is monitored by many more people and they will happily try
|
||||
to help you with whatever issue you have. This repository's PRs and issues
|
||||
should be opened only for dealing with issues pertaining to specific way this
|
||||
libbpf mirror repo is set up and organized.
|
||||
Other header files at this repo (`include/linux/*.h`) are reduced versions of
|
||||
their counterpart files at bpf-next's `tools/include/linux/*.h` to make compilation
|
||||
successful.
|
||||
|
||||
Build
|
||||
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
||||
[](https://travis-ci.org/libbpf/libbpf)
|
||||
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
||||
[](https://scan.coverity.com/projects/libbpf)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libbpf)
|
||||
=====
|
||||
libelf is an internal dependency of libbpf and thus it is required to link
|
||||
against and must be installed on the system for applications to work.
|
||||
pkg-config is used by default to find libelf, and the program called can be
|
||||
overridden with `PKG_CONFIG`.
|
||||
|
||||
If using `pkg-config` at build time is not desired, it can be disabled by
|
||||
setting `NO_PKG_CONFIG=1` when calling make.
|
||||
If using `pkg-config` at build time is not desired, it can be disabled by setting
|
||||
`NO_PKG_CONFIG=1` when calling make.
|
||||
|
||||
To build both static libbpf.a and shared libbpf.so:
|
||||
```bash
|
||||
@@ -73,6 +51,29 @@ $ cd src
|
||||
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
||||
```
|
||||
|
||||
Distributions
|
||||
=============
|
||||
|
||||
Distributions packaging libbpf from this mirror:
|
||||
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
||||
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||
- [Debian](https://packages.debian.org/sid/libbpf-dev)
|
||||
|
||||
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||
- Consistent versioning across distributions.
|
||||
- No ties to any specific kernel, transparent handling of older kernels.
|
||||
Libbpf is designed to be kernel-agnostic and work across multitude of kernel
|
||||
versions. It has built-in mechanisms to gracefully handle older kernels,
|
||||
that are missing some of the features, by working around or gracefully
|
||||
degrading functionality. Thus libbpf is not tied to a specific kernel
|
||||
version and can/should be packaged and versioned independently.
|
||||
- Continuous integration testing via [TravisCI](https://travis-ci.org/libbpf/libbpf).
|
||||
- Static code analysis via [LGTM](https://lgtm.com/projects/g/libbpf/libbpf) and [Coverity](https://scan.coverity.com/projects/libbpf).
|
||||
|
||||
Package dependencies of libbpf, package names may vary across distros:
|
||||
- zlib
|
||||
- libelf
|
||||
|
||||
BPF CO-RE (Compile Once – Run Everywhere)
|
||||
=========================================
|
||||
|
||||
@@ -88,9 +89,6 @@ Some major Linux distributions come with kernel BTF already built in:
|
||||
- RHEL 8.2+
|
||||
- OpenSUSE Tumbleweed (in the next release, as of 2020-06-04)
|
||||
- Arch Linux (from kernel 5.7.1.arch1-1)
|
||||
- Manjaro (from kernel 5.4 if compiled after 2021-06-18)
|
||||
- Ubuntu 20.10
|
||||
- Debian 11 (amd64/arm64)
|
||||
|
||||
If your kernel doesn't come with BTF built-in, you'll need to build custom
|
||||
kernel. You'll need:
|
||||
@@ -110,52 +108,18 @@ distributions have Clang/LLVM 10+ packaged by default:
|
||||
- Fedora 32+
|
||||
- Ubuntu 20.04+
|
||||
- Arch Linux
|
||||
- Ubuntu 20.10 (LLVM 11)
|
||||
- Debian 11 (LLVM 11)
|
||||
- Alpine 3.13+
|
||||
|
||||
Otherwise, please make sure to update it on your system.
|
||||
|
||||
The following resources are useful to understand what BPF CO-RE is and how to
|
||||
use it:
|
||||
- [BPF CO-RE reference guide](https://nakryiko.com/posts/bpf-core-reference-guide/)
|
||||
- [BPF Portability and CO-RE](https://nakryiko.com/posts/bpf-portability-and-co-re/)
|
||||
- [HOWTO: BCC to libbpf conversion](https://nakryiko.com/posts/bcc-to-libbpf-howto-guide/)
|
||||
- [BPF Portability and CO-RE](https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html)
|
||||
- [HOWTO: BCC to libbpf conversion](https://facebookmicrosites.github.io/bpf/blog/2020/02/20/bcc-to-libbpf-howto-guide.html)
|
||||
- [libbpf-tools in BCC repo](https://github.com/iovisor/bcc/tree/master/libbpf-tools)
|
||||
contain lots of real-world tools converted from BCC to BPF CO-RE. Consider
|
||||
converting some more to both contribute to the BPF community and gain some
|
||||
more experience with it.
|
||||
|
||||
Distributions
|
||||
=============
|
||||
|
||||
Distributions packaging libbpf from this mirror:
|
||||
- [Fedora](https://src.fedoraproject.org/rpms/libbpf)
|
||||
- [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
|
||||
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
||||
- [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
|
||||
- [Ubuntu](https://packages.ubuntu.com/source/impish/libbpf)
|
||||
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
||||
|
||||
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||
- Consistent versioning across distributions.
|
||||
- No ties to any specific kernel, transparent handling of older kernels.
|
||||
Libbpf is designed to be kernel-agnostic and work across multitude of
|
||||
kernel versions. It has built-in mechanisms to gracefully handle older
|
||||
kernels, that are missing some of the features, by working around or
|
||||
gracefully degrading functionality. Thus libbpf is not tied to a specific
|
||||
kernel version and can/should be packaged and versioned independently.
|
||||
- Continuous integration testing via
|
||||
[TravisCI](https://travis-ci.org/libbpf/libbpf).
|
||||
- Static code analysis via [LGTM](https://lgtm.com/projects/g/libbpf/libbpf)
|
||||
and [Coverity](https://scan.coverity.com/projects/libbpf).
|
||||
|
||||
Package dependencies of libbpf, package names may vary across distros:
|
||||
- zlib
|
||||
- libelf
|
||||
|
||||
[](https://repology.org/project/libbpf/versions)
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
|
||||
2
docs/.gitignore
vendored
2
docs/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
sphinx/build
|
||||
sphinx/doxygen/build
|
||||
93
docs/api.rst
93
docs/api.rst
@@ -1,93 +0,0 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
.. _api:
|
||||
|
||||
.. toctree:: Table of Contents
|
||||
|
||||
|
||||
LIBBPF API
|
||||
==========
|
||||
|
||||
Error Handling
|
||||
--------------
|
||||
|
||||
When libbpf is used in "libbpf 1.0 mode", API functions can return errors in one of two ways.
|
||||
|
||||
You can set "libbpf 1.0" mode with the following line:
|
||||
|
||||
.. code-block::
|
||||
|
||||
libbpf_set_strict_mode(LIBBPF_STRICT_DIRECT_ERRS | LIBBPF_STRICT_CLEAN_PTRS);
|
||||
|
||||
If the function returns an error code directly, it uses 0 to indicate success
|
||||
and a negative error code to indicate what caused the error. In this case the
|
||||
error code should be checked directly from the return, you do not need to check
|
||||
errno.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block::
|
||||
|
||||
err = some_libbpf_api_with_error_return(...);
|
||||
if (err < 0) {
|
||||
/* Handle error accordingly */
|
||||
}
|
||||
|
||||
If the function returns a pointer, it will return NULL to indicate there was
|
||||
an error. In this case errno should be checked for the error code.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block::
|
||||
|
||||
ptr = some_libbpf_api_returning_ptr();
|
||||
if (!ptr) {
|
||||
/* note no minus sign for EINVAL and E2BIG below */
|
||||
if (errno == EINVAL) {
|
||||
/* handle EINVAL error */
|
||||
} else if (errno == E2BIG) {
|
||||
/* handle E2BIG error */
|
||||
}
|
||||
}
|
||||
|
||||
libbpf.h
|
||||
--------
|
||||
.. doxygenfile:: libbpf.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
bpf.h
|
||||
-----
|
||||
.. doxygenfile:: bpf.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
btf.h
|
||||
-----
|
||||
.. doxygenfile:: btf.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
xsk.h
|
||||
-----
|
||||
.. doxygenfile:: xsk.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
bpf_tracing.h
|
||||
-------------
|
||||
.. doxygenfile:: bpf_tracing.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
bpf_core_read.h
|
||||
---------------
|
||||
.. doxygenfile:: bpf_core_read.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
|
||||
bpf_endian.h
|
||||
------------
|
||||
.. doxygenfile:: bpf_endian.h
|
||||
:project: libbpf
|
||||
:sections: func define public-type enum
|
||||
40
docs/conf.py
40
docs/conf.py
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
project = "libbpf"
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.imgmath',
|
||||
'sphinx.ext.todo',
|
||||
'breathe',
|
||||
]
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
if read_the_docs_build:
|
||||
subprocess.call('cd sphinx ; make clean', shell=True)
|
||||
subprocess.call('cd sphinx/doxygen ; doxygen', shell=True)
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
breathe_projects = { "libbpf": "./sphinx/doxygen/build/xml/" }
|
||||
breathe_default_project = "libbpf"
|
||||
breathe_show_define_initializer = True
|
||||
breathe_show_enumvalue_initializer = True
|
||||
@@ -1,21 +0,0 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
libbpf
|
||||
======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
API Documentation <https://libbpf.readthedocs.io/en/latest/api.html>
|
||||
libbpf_naming_convention
|
||||
libbpf_build
|
||||
|
||||
This is documentation for libbpf, a userspace library for loading and
|
||||
interacting with bpf programs.
|
||||
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
||||
their application, should be sent to bpf@vger.kernel.org mailing list.
|
||||
You can `subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the
|
||||
mailing list search its `archive <https://lore.kernel.org/bpf/>`_.
|
||||
Please search the archive before asking new questions. It very well might
|
||||
be that this was already addressed or answered before.
|
||||
@@ -1,37 +0,0 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
Building libbpf
|
||||
===============
|
||||
|
||||
libelf and zlib are internal dependencies of libbpf and thus are required to link
|
||||
against and must be installed on the system for applications to work.
|
||||
pkg-config is used by default to find libelf, and the program called
|
||||
can be overridden with PKG_CONFIG.
|
||||
|
||||
If using pkg-config at build time is not desired, it can be disabled by
|
||||
setting NO_PKG_CONFIG=1 when calling make.
|
||||
|
||||
To build both static libbpf.a and shared libbpf.so:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd src
|
||||
$ make
|
||||
|
||||
To build only static libbpf.a library in directory build/ and install them
|
||||
together with libbpf headers in a staging directory root/:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd src
|
||||
$ mkdir build root
|
||||
$ BUILD_STATIC_ONLY=y OBJDIR=build DESTDIR=root make install
|
||||
|
||||
To build both static libbpf.a and shared libbpf.so against a custom libelf
|
||||
dependency installed in /build/root/ and install them together with libbpf
|
||||
headers in a build directory /build/root/:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd src
|
||||
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make
|
||||
@@ -1,9 +0,0 @@
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = ../src
|
||||
BUILDDIR = build
|
||||
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)"
|
||||
|
||||
%:
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)"
|
||||
@@ -1,277 +0,0 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "libbpf"
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_BRIEF =
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = ./build
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_BANNER = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
PYTHON_DOCSTRING = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
OPTIMIZE_OUTPUT_SLICE = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
AUTOLINK_SUPPORT = YES
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
NUM_PROC_THREADS = 1
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PRIV_VIRTUAL = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
CITE_BIB_FILES =
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
INPUT = ../../../src
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c \
|
||||
*.h
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS = ___*
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE = YES
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
ALPHABETICAL_INDEX = YES
|
||||
IGNORE_PREFIX =
|
||||
GENERATE_HTML = NO
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
HTML_FORMULA_FORMAT = png
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
FORMULA_MACROFILE =
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME =
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_STYLESHEET =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
RTF_SOURCE_CODE = NO
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_SUBDIR =
|
||||
MAN_LINKS = NO
|
||||
GENERATE_XML = YES
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
XML_NS_MEMB_FILE_SCOPE = NO
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = NO
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
CLASS_DIAGRAMS = YES
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
DOT_UML_DETAILS = NO
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
INTERACTIVE_SVG = NO
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
PLANTUML_JAR_PATH =
|
||||
PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
@@ -1 +0,0 @@
|
||||
breathe
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "libbpf.h"
|
||||
|
||||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
struct bpf_object *obj = NULL;
|
||||
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
|
||||
int err;
|
||||
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
|
||||
opts.object_name = "fuzz-object";
|
||||
obj = bpf_object__open_mem(data, size, &opts);
|
||||
err = libbpf_get_error(obj);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
bpf_object__close(obj);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -5,22 +5,6 @@
|
||||
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = CODE, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = SRC, \
|
||||
.off = OFF, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_ALU32_IMM(OP, DST, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU | BPF_OP(OP) | BPF_K, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_ALU64_IMM(OP, DST, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
|
||||
|
||||
@@ -72,20 +72,11 @@ static inline void list_del(struct list_head *entry)
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
#define list_next_entry(pos, member) \
|
||||
list_entry((pos)->member.next, typeof(*(pos)), member)
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_first_entry(head, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/posix_types.h>
|
||||
|
||||
|
||||
20
include/tools/libc_compat.h
Normal file
20
include/tools/libc_compat.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.0+ OR BSD-2-Clause)
|
||||
/* Copyright (C) 2018 Netronome Systems, Inc. */
|
||||
|
||||
#ifndef __TOOLS_LIBC_COMPAT_H
|
||||
#define __TOOLS_LIBC_COMPAT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <linux/overflow.h>
|
||||
|
||||
#ifdef COMPAT_NEED_REALLOCARRAY
|
||||
static inline void *reallocarray(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(nmemb, size, &bytes)))
|
||||
return NULL;
|
||||
return realloc(ptr, bytes);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,8 @@ struct btf_type {
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
@@ -43,7 +43,7 @@ struct btf_type {
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG.
|
||||
* FUNC, FUNC_PROTO and VAR.
|
||||
* "type" is a type_id referring to another type.
|
||||
*/
|
||||
union {
|
||||
@@ -52,34 +52,28 @@ struct btf_type {
|
||||
};
|
||||
};
|
||||
|
||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
|
||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||
|
||||
enum {
|
||||
BTF_KIND_UNKN = 0, /* Unknown */
|
||||
BTF_KIND_INT = 1, /* Integer */
|
||||
BTF_KIND_PTR = 2, /* Pointer */
|
||||
BTF_KIND_ARRAY = 3, /* Array */
|
||||
BTF_KIND_STRUCT = 4, /* Struct */
|
||||
BTF_KIND_UNION = 5, /* Union */
|
||||
BTF_KIND_ENUM = 6, /* Enumeration */
|
||||
BTF_KIND_FWD = 7, /* Forward */
|
||||
BTF_KIND_TYPEDEF = 8, /* Typedef */
|
||||
BTF_KIND_VOLATILE = 9, /* Volatile */
|
||||
BTF_KIND_CONST = 10, /* Const */
|
||||
BTF_KIND_RESTRICT = 11, /* Restrict */
|
||||
BTF_KIND_FUNC = 12, /* Function */
|
||||
BTF_KIND_FUNC_PROTO = 13, /* Function Proto */
|
||||
BTF_KIND_VAR = 14, /* Variable */
|
||||
BTF_KIND_DATASEC = 15, /* Section */
|
||||
BTF_KIND_FLOAT = 16, /* Floating point */
|
||||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
|
||||
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
};
|
||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||
#define BTF_KIND_INT 1 /* Integer */
|
||||
#define BTF_KIND_PTR 2 /* Pointer */
|
||||
#define BTF_KIND_ARRAY 3 /* Array */
|
||||
#define BTF_KIND_STRUCT 4 /* Struct */
|
||||
#define BTF_KIND_UNION 5 /* Union */
|
||||
#define BTF_KIND_ENUM 6 /* Enumeration */
|
||||
#define BTF_KIND_FWD 7 /* Forward */
|
||||
#define BTF_KIND_TYPEDEF 8 /* Typedef */
|
||||
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
||||
#define BTF_KIND_CONST 10 /* Const */
|
||||
#define BTF_KIND_RESTRICT 11 /* Restrict */
|
||||
#define BTF_KIND_FUNC 12 /* Function */
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||
#define BTF_KIND_VAR 14 /* Variable */
|
||||
#define BTF_KIND_DATASEC 15 /* Section */
|
||||
#define BTF_KIND_MAX BTF_KIND_DATASEC
|
||||
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
|
||||
|
||||
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
||||
* followed by extra data.
|
||||
@@ -175,15 +169,4 @@ struct btf_var_secinfo {
|
||||
__u32 size;
|
||||
};
|
||||
|
||||
/* BTF_KIND_DECL_TAG is followed by a single "struct btf_decl_tag" to describe
|
||||
* additional information related to the tag applied location.
|
||||
* If component_idx == -1, the tag is applied to a struct, union,
|
||||
* variable or function. Otherwise, it is applied to a struct/union
|
||||
* member or a func argument, and component_idx indicates which member
|
||||
* or argument (0 ... vlen-1).
|
||||
*/
|
||||
struct btf_decl_tag {
|
||||
__s32 component_idx;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BTF_H__ */
|
||||
|
||||
@@ -7,23 +7,24 @@
|
||||
|
||||
/* This struct should be in sync with struct rtnl_link_stats64 */
|
||||
struct rtnl_link_stats {
|
||||
__u32 rx_packets;
|
||||
__u32 tx_packets;
|
||||
__u32 rx_bytes;
|
||||
__u32 tx_bytes;
|
||||
__u32 rx_errors;
|
||||
__u32 tx_errors;
|
||||
__u32 rx_dropped;
|
||||
__u32 tx_dropped;
|
||||
__u32 multicast;
|
||||
__u32 rx_packets; /* total packets received */
|
||||
__u32 tx_packets; /* total packets transmitted */
|
||||
__u32 rx_bytes; /* total bytes received */
|
||||
__u32 tx_bytes; /* total bytes transmitted */
|
||||
__u32 rx_errors; /* bad packets received */
|
||||
__u32 tx_errors; /* packet transmit problems */
|
||||
__u32 rx_dropped; /* no space in linux buffers */
|
||||
__u32 tx_dropped; /* no space available in linux */
|
||||
__u32 multicast; /* multicast packets received */
|
||||
__u32 collisions;
|
||||
|
||||
/* detailed rx_errors: */
|
||||
__u32 rx_length_errors;
|
||||
__u32 rx_over_errors;
|
||||
__u32 rx_crc_errors;
|
||||
__u32 rx_frame_errors;
|
||||
__u32 rx_fifo_errors;
|
||||
__u32 rx_missed_errors;
|
||||
__u32 rx_over_errors; /* receiver ring buff overflow */
|
||||
__u32 rx_crc_errors; /* recved pkt with crc error */
|
||||
__u32 rx_frame_errors; /* recv'd frame alignment error */
|
||||
__u32 rx_fifo_errors; /* recv'r fifo overrun */
|
||||
__u32 rx_missed_errors; /* receiver missed packet */
|
||||
|
||||
/* detailed tx_errors */
|
||||
__u32 tx_aborted_errors;
|
||||
@@ -36,201 +37,29 @@ struct rtnl_link_stats {
|
||||
__u32 rx_compressed;
|
||||
__u32 tx_compressed;
|
||||
|
||||
__u32 rx_nohandler;
|
||||
__u32 rx_nohandler; /* dropped, no handler found */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rtnl_link_stats64 - The main device statistics structure.
|
||||
*
|
||||
* @rx_packets: Number of good packets received by the interface.
|
||||
* For hardware interfaces counts all good packets received from the device
|
||||
* by the host, including packets which host had to drop at various stages
|
||||
* of processing (even in the driver).
|
||||
*
|
||||
* @tx_packets: Number of packets successfully transmitted.
|
||||
* For hardware interfaces counts packets which host was able to successfully
|
||||
* hand over to the device, which does not necessarily mean that packets
|
||||
* had been successfully transmitted out of the device, only that device
|
||||
* acknowledged it copied them out of host memory.
|
||||
*
|
||||
* @rx_bytes: Number of good received bytes, corresponding to @rx_packets.
|
||||
*
|
||||
* For IEEE 802.3 devices should count the length of Ethernet Frames
|
||||
* excluding the FCS.
|
||||
*
|
||||
* @tx_bytes: Number of good transmitted bytes, corresponding to @tx_packets.
|
||||
*
|
||||
* For IEEE 802.3 devices should count the length of Ethernet Frames
|
||||
* excluding the FCS.
|
||||
*
|
||||
* @rx_errors: Total number of bad packets received on this network device.
|
||||
* This counter must include events counted by @rx_length_errors,
|
||||
* @rx_crc_errors, @rx_frame_errors and other errors not otherwise
|
||||
* counted.
|
||||
*
|
||||
* @tx_errors: Total number of transmit problems.
|
||||
* This counter must include events counter by @tx_aborted_errors,
|
||||
* @tx_carrier_errors, @tx_fifo_errors, @tx_heartbeat_errors,
|
||||
* @tx_window_errors and other errors not otherwise counted.
|
||||
*
|
||||
* @rx_dropped: Number of packets received but not processed,
|
||||
* e.g. due to lack of resources or unsupported protocol.
|
||||
* For hardware interfaces this counter may include packets discarded
|
||||
* due to L2 address filtering but should not include packets dropped
|
||||
* by the device due to buffer exhaustion which are counted separately in
|
||||
* @rx_missed_errors (since procfs folds those two counters together).
|
||||
*
|
||||
* @tx_dropped: Number of packets dropped on their way to transmission,
|
||||
* e.g. due to lack of resources.
|
||||
*
|
||||
* @multicast: Multicast packets received.
|
||||
* For hardware interfaces this statistic is commonly calculated
|
||||
* at the device level (unlike @rx_packets) and therefore may include
|
||||
* packets which did not reach the host.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter may be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.21 aMulticastFramesReceivedOK
|
||||
*
|
||||
* @collisions: Number of collisions during packet transmissions.
|
||||
*
|
||||
* @rx_length_errors: Number of packets dropped due to invalid length.
|
||||
* Part of aggregate "frame" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter should be equivalent to a sum
|
||||
* of the following attributes:
|
||||
*
|
||||
* - 30.3.1.1.23 aInRangeLengthErrors
|
||||
* - 30.3.1.1.24 aOutOfRangeLengthField
|
||||
* - 30.3.1.1.25 aFrameTooLongErrors
|
||||
*
|
||||
* @rx_over_errors: Receiver FIFO overflow event counter.
|
||||
*
|
||||
* Historically the count of overflow events. Such events may be
|
||||
* reported in the receive descriptors or via interrupts, and may
|
||||
* not correspond one-to-one with dropped packets.
|
||||
*
|
||||
* The recommended interpretation for high speed interfaces is -
|
||||
* number of packets dropped because they did not fit into buffers
|
||||
* provided by the host, e.g. packets larger than MTU or next buffer
|
||||
* in the ring was not available for a scatter transfer.
|
||||
*
|
||||
* Part of aggregate "frame" errors in `/proc/net/dev`.
|
||||
*
|
||||
* This statistics was historically used interchangeably with
|
||||
* @rx_fifo_errors.
|
||||
*
|
||||
* This statistic corresponds to hardware events and is not commonly used
|
||||
* on software devices.
|
||||
*
|
||||
* @rx_crc_errors: Number of packets received with a CRC error.
|
||||
* Part of aggregate "frame" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter must be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.6 aFrameCheckSequenceErrors
|
||||
*
|
||||
* @rx_frame_errors: Receiver frame alignment errors.
|
||||
* Part of aggregate "frame" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter should be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.7 aAlignmentErrors
|
||||
*
|
||||
* @rx_fifo_errors: Receiver FIFO error counter.
|
||||
*
|
||||
* Historically the count of overflow events. Those events may be
|
||||
* reported in the receive descriptors or via interrupts, and may
|
||||
* not correspond one-to-one with dropped packets.
|
||||
*
|
||||
* This statistics was used interchangeably with @rx_over_errors.
|
||||
* Not recommended for use in drivers for high speed interfaces.
|
||||
*
|
||||
* This statistic is used on software devices, e.g. to count software
|
||||
* packet queue overflow (can) or sequencing errors (GRE).
|
||||
*
|
||||
* @rx_missed_errors: Count of packets missed by the host.
|
||||
* Folded into the "drop" counter in `/proc/net/dev`.
|
||||
*
|
||||
* Counts number of packets dropped by the device due to lack
|
||||
* of buffer space. This usually indicates that the host interface
|
||||
* is slower than the network interface, or host is not keeping up
|
||||
* with the receive packet rate.
|
||||
*
|
||||
* This statistic corresponds to hardware events and is not used
|
||||
* on software devices.
|
||||
*
|
||||
* @tx_aborted_errors:
|
||||
* Part of aggregate "carrier" errors in `/proc/net/dev`.
|
||||
* For IEEE 802.3 devices capable of half-duplex operation this counter
|
||||
* must be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.11 aFramesAbortedDueToXSColls
|
||||
*
|
||||
* High speed interfaces may use this counter as a general device
|
||||
* discard counter.
|
||||
*
|
||||
* @tx_carrier_errors: Number of frame transmission errors due to loss
|
||||
* of carrier during transmission.
|
||||
* Part of aggregate "carrier" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter must be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.13 aCarrierSenseErrors
|
||||
*
|
||||
* @tx_fifo_errors: Number of frame transmission errors due to device
|
||||
* FIFO underrun / underflow. This condition occurs when the device
|
||||
* begins transmission of a frame but is unable to deliver the
|
||||
* entire frame to the transmitter in time for transmission.
|
||||
* Part of aggregate "carrier" errors in `/proc/net/dev`.
|
||||
*
|
||||
* @tx_heartbeat_errors: Number of Heartbeat / SQE Test errors for
|
||||
* old half-duplex Ethernet.
|
||||
* Part of aggregate "carrier" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices possibly equivalent to:
|
||||
*
|
||||
* - 30.3.2.1.4 aSQETestErrors
|
||||
*
|
||||
* @tx_window_errors: Number of frame transmission errors due
|
||||
* to late collisions (for Ethernet - after the first 64B of transmission).
|
||||
* Part of aggregate "carrier" errors in `/proc/net/dev`.
|
||||
*
|
||||
* For IEEE 802.3 devices this counter must be equivalent to:
|
||||
*
|
||||
* - 30.3.1.1.10 aLateCollisions
|
||||
*
|
||||
* @rx_compressed: Number of correctly received compressed packets.
|
||||
* This counters is only meaningful for interfaces which support
|
||||
* packet compression (e.g. CSLIP, PPP).
|
||||
*
|
||||
* @tx_compressed: Number of transmitted compressed packets.
|
||||
* This counters is only meaningful for interfaces which support
|
||||
* packet compression (e.g. CSLIP, PPP).
|
||||
*
|
||||
* @rx_nohandler: Number of packets received on the interface
|
||||
* but dropped by the networking stack because the device is
|
||||
* not designated to receive packets (e.g. backup link in a bond).
|
||||
*/
|
||||
/* The main device statistics structure */
|
||||
struct rtnl_link_stats64 {
|
||||
__u64 rx_packets;
|
||||
__u64 tx_packets;
|
||||
__u64 rx_bytes;
|
||||
__u64 tx_bytes;
|
||||
__u64 rx_errors;
|
||||
__u64 tx_errors;
|
||||
__u64 rx_dropped;
|
||||
__u64 tx_dropped;
|
||||
__u64 multicast;
|
||||
__u64 rx_packets; /* total packets received */
|
||||
__u64 tx_packets; /* total packets transmitted */
|
||||
__u64 rx_bytes; /* total bytes received */
|
||||
__u64 tx_bytes; /* total bytes transmitted */
|
||||
__u64 rx_errors; /* bad packets received */
|
||||
__u64 tx_errors; /* packet transmit problems */
|
||||
__u64 rx_dropped; /* no space in linux buffers */
|
||||
__u64 tx_dropped; /* no space available in linux */
|
||||
__u64 multicast; /* multicast packets received */
|
||||
__u64 collisions;
|
||||
|
||||
/* detailed rx_errors: */
|
||||
__u64 rx_length_errors;
|
||||
__u64 rx_over_errors;
|
||||
__u64 rx_crc_errors;
|
||||
__u64 rx_frame_errors;
|
||||
__u64 rx_fifo_errors;
|
||||
__u64 rx_missed_errors;
|
||||
__u64 rx_over_errors; /* receiver ring buff overflow */
|
||||
__u64 rx_crc_errors; /* recved pkt with crc error */
|
||||
__u64 rx_frame_errors; /* recv'd frame alignment error */
|
||||
__u64 rx_fifo_errors; /* recv'r fifo overrun */
|
||||
__u64 rx_missed_errors; /* receiver missed packet */
|
||||
|
||||
/* detailed tx_errors */
|
||||
__u64 tx_aborted_errors;
|
||||
@@ -242,7 +71,8 @@ struct rtnl_link_stats64 {
|
||||
/* for cslip etc */
|
||||
__u64 rx_compressed;
|
||||
__u64 tx_compressed;
|
||||
__u64 rx_nohandler;
|
||||
|
||||
__u64 rx_nohandler; /* dropped, no handler found */
|
||||
};
|
||||
|
||||
/* The struct should be in sync with struct ifmap */
|
||||
@@ -340,30 +170,12 @@ enum {
|
||||
IFLA_PROP_LIST,
|
||||
IFLA_ALT_IFNAME, /* Alternative ifname */
|
||||
IFLA_PERM_ADDRESS,
|
||||
IFLA_PROTO_DOWN_REASON,
|
||||
|
||||
/* device (sysfs) name as parent, used instead
|
||||
* of IFLA_LINK where there's no parent netdev
|
||||
*/
|
||||
IFLA_PARENT_DEV_NAME,
|
||||
IFLA_PARENT_DEV_BUS_NAME,
|
||||
IFLA_GRO_MAX_SIZE,
|
||||
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
|
||||
#define IFLA_MAX (__IFLA_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_PROTO_DOWN_REASON_UNSPEC,
|
||||
IFLA_PROTO_DOWN_REASON_MASK, /* u32, mask for reason bits */
|
||||
IFLA_PROTO_DOWN_REASON_VALUE, /* u32, reason bit value */
|
||||
|
||||
__IFLA_PROTO_DOWN_REASON_CNT,
|
||||
IFLA_PROTO_DOWN_REASON_MAX = __IFLA_PROTO_DOWN_REASON_CNT - 1
|
||||
};
|
||||
|
||||
/* backwards compatibility for userspace */
|
||||
#ifndef __KERNEL__
|
||||
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
|
||||
@@ -418,7 +230,6 @@ enum {
|
||||
IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
|
||||
IFLA_INET6_TOKEN, /* device token */
|
||||
IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
|
||||
IFLA_INET6_RA_MTU, /* mtu carried in the RA message */
|
||||
__IFLA_INET6_MAX
|
||||
};
|
||||
|
||||
@@ -481,7 +292,6 @@ enum {
|
||||
IFLA_BR_MCAST_MLD_VERSION,
|
||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||
IFLA_BR_MULTI_BOOLOPT,
|
||||
IFLA_BR_MCAST_QUERIER_STATE,
|
||||
__IFLA_BR_MAX,
|
||||
};
|
||||
|
||||
@@ -534,9 +344,6 @@ enum {
|
||||
IFLA_BRPORT_ISOLATED,
|
||||
IFLA_BRPORT_BACKUP_PORT,
|
||||
IFLA_BRPORT_MRP_RING_OPEN,
|
||||
IFLA_BRPORT_MRP_IN_OPEN,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
|
||||
IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
@@ -601,8 +408,6 @@ enum {
|
||||
IFLA_MACVLAN_MACADDR,
|
||||
IFLA_MACVLAN_MACADDR_DATA,
|
||||
IFLA_MACVLAN_MACADDR_COUNT,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
|
||||
__IFLA_MACVLAN_MAX,
|
||||
};
|
||||
|
||||
@@ -624,7 +429,6 @@ enum macvlan_macaddr_mode {
|
||||
};
|
||||
|
||||
#define MACVLAN_FLAG_NOPROMISC 1
|
||||
#define MACVLAN_FLAG_NODST 2 /* skip dst macvlan if matching src macvlan */
|
||||
|
||||
/* VRF section */
|
||||
enum {
|
||||
@@ -789,18 +593,6 @@ enum ifla_geneve_df {
|
||||
GENEVE_DF_MAX = __GENEVE_DF_END - 1,
|
||||
};
|
||||
|
||||
/* Bareudp section */
|
||||
enum {
|
||||
IFLA_BAREUDP_UNSPEC,
|
||||
IFLA_BAREUDP_PORT,
|
||||
IFLA_BAREUDP_ETHERTYPE,
|
||||
IFLA_BAREUDP_SRCPORT_MIN,
|
||||
IFLA_BAREUDP_MULTIPROTO_MODE,
|
||||
__IFLA_BAREUDP_MAX
|
||||
};
|
||||
|
||||
#define IFLA_BAREUDP_MAX (__IFLA_BAREUDP_MAX - 1)
|
||||
|
||||
/* PPP section */
|
||||
enum {
|
||||
IFLA_PPP_UNSPEC,
|
||||
@@ -858,9 +650,6 @@ enum {
|
||||
IFLA_BOND_AD_ACTOR_SYSTEM,
|
||||
IFLA_BOND_TLB_DYNAMIC_LB,
|
||||
IFLA_BOND_PEER_NOTIF_DELAY,
|
||||
IFLA_BOND_AD_LACP_ACTIVE,
|
||||
IFLA_BOND_MISSED_MAX,
|
||||
IFLA_BOND_NS_IP6_TARGET,
|
||||
__IFLA_BOND_MAX,
|
||||
};
|
||||
|
||||
@@ -1105,14 +894,7 @@ enum {
|
||||
#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
|
||||
|
||||
|
||||
/* HSR/PRP section, both uses same interface */
|
||||
|
||||
/* Different redundancy protocols for hsr device */
|
||||
enum {
|
||||
HSR_PROTOCOL_HSR,
|
||||
HSR_PROTOCOL_PRP,
|
||||
HSR_PROTOCOL_MAX,
|
||||
};
|
||||
/* HSR section */
|
||||
|
||||
enum {
|
||||
IFLA_HSR_UNSPEC,
|
||||
@@ -1122,9 +904,6 @@ enum {
|
||||
IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */
|
||||
IFLA_HSR_SEQ_NR,
|
||||
IFLA_HSR_VERSION, /* HSR version */
|
||||
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
|
||||
* HSR. For example PRP.
|
||||
*/
|
||||
__IFLA_HSR_MAX,
|
||||
};
|
||||
|
||||
@@ -1249,8 +1028,6 @@ enum {
|
||||
#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
|
||||
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
|
||||
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
|
||||
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5 (1U << 4)
|
||||
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV5 (1U << 5)
|
||||
|
||||
enum {
|
||||
IFLA_RMNET_UNSPEC,
|
||||
@@ -1266,14 +1043,4 @@ struct ifla_rmnet_flags {
|
||||
__u32 mask;
|
||||
};
|
||||
|
||||
/* MCTP section */
|
||||
|
||||
enum {
|
||||
IFLA_MCTP_UNSPEC,
|
||||
IFLA_MCTP_NET,
|
||||
__IFLA_MCTP_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
|
||||
|
||||
#endif /* _UAPI_LINUX_IF_LINK_H */
|
||||
|
||||
@@ -73,12 +73,9 @@ struct xdp_umem_reg {
|
||||
};
|
||||
|
||||
struct xdp_statistics {
|
||||
__u64 rx_dropped; /* Dropped for other reasons */
|
||||
__u64 rx_dropped; /* Dropped for reasons other than invalid desc */
|
||||
__u64 rx_invalid_descs; /* Dropped due to invalid descriptor */
|
||||
__u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
|
||||
__u64 rx_ring_full; /* Dropped due to rx ring being full */
|
||||
__u64 rx_fill_ring_empty_descs; /* Failed to retrieve item from fill ring */
|
||||
__u64 tx_ring_empty_descs; /* Failed to retrieve item from tx ring */
|
||||
};
|
||||
|
||||
struct xdp_options {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,612 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef __LINUX_PKT_CLS_H
|
||||
#define __LINUX_PKT_CLS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
|
||||
#define TC_COOKIE_MAX_SIZE 16
|
||||
|
||||
/* Action attributes */
|
||||
enum {
|
||||
TCA_ACT_UNSPEC,
|
||||
TCA_ACT_KIND,
|
||||
TCA_ACT_OPTIONS,
|
||||
TCA_ACT_INDEX,
|
||||
TCA_ACT_STATS,
|
||||
TCA_ACT_PAD,
|
||||
TCA_ACT_COOKIE,
|
||||
__TCA_ACT_MAX
|
||||
};
|
||||
|
||||
#define TCA_ACT_MAX __TCA_ACT_MAX
|
||||
#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
|
||||
#define TCA_ACT_MAX_PRIO 32
|
||||
#define TCA_ACT_BIND 1
|
||||
#define TCA_ACT_NOBIND 0
|
||||
#define TCA_ACT_UNBIND 1
|
||||
#define TCA_ACT_NOUNBIND 0
|
||||
#define TCA_ACT_REPLACE 1
|
||||
#define TCA_ACT_NOREPLACE 0
|
||||
|
||||
#define TC_ACT_UNSPEC (-1)
|
||||
#define TC_ACT_OK 0
|
||||
#define TC_ACT_RECLASSIFY 1
|
||||
#define TC_ACT_SHOT 2
|
||||
#define TC_ACT_PIPE 3
|
||||
#define TC_ACT_STOLEN 4
|
||||
#define TC_ACT_QUEUED 5
|
||||
#define TC_ACT_REPEAT 6
|
||||
#define TC_ACT_REDIRECT 7
|
||||
#define TC_ACT_TRAP 8 /* For hw path, this means "trap to cpu"
|
||||
* and don't further process the frame
|
||||
* in hardware. For sw path, this is
|
||||
* equivalent of TC_ACT_STOLEN - drop
|
||||
* the skb and act like everything
|
||||
* is alright.
|
||||
*/
|
||||
#define TC_ACT_VALUE_MAX TC_ACT_TRAP
|
||||
|
||||
/* There is a special kind of actions called "extended actions",
|
||||
* which need a value parameter. These have a local opcode located in
|
||||
* the highest nibble, starting from 1. The rest of the bits
|
||||
* are used to carry the value. These two parts together make
|
||||
* a combined opcode.
|
||||
*/
|
||||
#define __TC_ACT_EXT_SHIFT 28
|
||||
#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT)
|
||||
#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1)
|
||||
#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK))
|
||||
#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode)
|
||||
|
||||
#define TC_ACT_JUMP __TC_ACT_EXT(1)
|
||||
#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
|
||||
#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN
|
||||
|
||||
/* Action type identifiers*/
|
||||
enum {
|
||||
TCA_ID_UNSPEC=0,
|
||||
TCA_ID_POLICE=1,
|
||||
/* other actions go here */
|
||||
__TCA_ID_MAX=255
|
||||
};
|
||||
|
||||
#define TCA_ID_MAX __TCA_ID_MAX
|
||||
|
||||
struct tc_police {
|
||||
__u32 index;
|
||||
int action;
|
||||
#define TC_POLICE_UNSPEC TC_ACT_UNSPEC
|
||||
#define TC_POLICE_OK TC_ACT_OK
|
||||
#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY
|
||||
#define TC_POLICE_SHOT TC_ACT_SHOT
|
||||
#define TC_POLICE_PIPE TC_ACT_PIPE
|
||||
|
||||
__u32 limit;
|
||||
__u32 burst;
|
||||
__u32 mtu;
|
||||
struct tc_ratespec rate;
|
||||
struct tc_ratespec peakrate;
|
||||
int refcnt;
|
||||
int bindcnt;
|
||||
__u32 capab;
|
||||
};
|
||||
|
||||
struct tcf_t {
|
||||
__u64 install;
|
||||
__u64 lastuse;
|
||||
__u64 expires;
|
||||
__u64 firstuse;
|
||||
};
|
||||
|
||||
struct tc_cnt {
|
||||
int refcnt;
|
||||
int bindcnt;
|
||||
};
|
||||
|
||||
#define tc_gen \
|
||||
__u32 index; \
|
||||
__u32 capab; \
|
||||
int action; \
|
||||
int refcnt; \
|
||||
int bindcnt
|
||||
|
||||
enum {
|
||||
TCA_POLICE_UNSPEC,
|
||||
TCA_POLICE_TBF,
|
||||
TCA_POLICE_RATE,
|
||||
TCA_POLICE_PEAKRATE,
|
||||
TCA_POLICE_AVRATE,
|
||||
TCA_POLICE_RESULT,
|
||||
TCA_POLICE_TM,
|
||||
TCA_POLICE_PAD,
|
||||
__TCA_POLICE_MAX
|
||||
#define TCA_POLICE_RESULT TCA_POLICE_RESULT
|
||||
};
|
||||
|
||||
#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
|
||||
|
||||
/* tca flags definitions */
|
||||
#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) /* don't offload filter to HW */
|
||||
#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) /* don't use filter in SW */
|
||||
#define TCA_CLS_FLAGS_IN_HW (1 << 2) /* filter is offloaded to HW */
|
||||
#define TCA_CLS_FLAGS_NOT_IN_HW (1 << 3) /* filter isn't offloaded to HW */
|
||||
#define TCA_CLS_FLAGS_VERBOSE (1 << 4) /* verbose logging */
|
||||
|
||||
/* U32 filters */
|
||||
|
||||
#define TC_U32_HTID(h) ((h)&0xFFF00000)
|
||||
#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
|
||||
#define TC_U32_HASH(h) (((h)>>12)&0xFF)
|
||||
#define TC_U32_NODE(h) ((h)&0xFFF)
|
||||
#define TC_U32_KEY(h) ((h)&0xFFFFF)
|
||||
#define TC_U32_UNSPEC 0
|
||||
#define TC_U32_ROOT (0xFFF00000)
|
||||
|
||||
enum {
|
||||
TCA_U32_UNSPEC,
|
||||
TCA_U32_CLASSID,
|
||||
TCA_U32_HASH,
|
||||
TCA_U32_LINK,
|
||||
TCA_U32_DIVISOR,
|
||||
TCA_U32_SEL,
|
||||
TCA_U32_POLICE,
|
||||
TCA_U32_ACT,
|
||||
TCA_U32_INDEV,
|
||||
TCA_U32_PCNT,
|
||||
TCA_U32_MARK,
|
||||
TCA_U32_FLAGS,
|
||||
TCA_U32_PAD,
|
||||
__TCA_U32_MAX
|
||||
};
|
||||
|
||||
#define TCA_U32_MAX (__TCA_U32_MAX - 1)
|
||||
|
||||
struct tc_u32_key {
|
||||
__be32 mask;
|
||||
__be32 val;
|
||||
int off;
|
||||
int offmask;
|
||||
};
|
||||
|
||||
struct tc_u32_sel {
|
||||
unsigned char flags;
|
||||
unsigned char offshift;
|
||||
unsigned char nkeys;
|
||||
|
||||
__be16 offmask;
|
||||
__u16 off;
|
||||
short offoff;
|
||||
|
||||
short hoff;
|
||||
__be32 hmask;
|
||||
struct tc_u32_key keys[0];
|
||||
};
|
||||
|
||||
struct tc_u32_mark {
|
||||
__u32 val;
|
||||
__u32 mask;
|
||||
__u32 success;
|
||||
};
|
||||
|
||||
struct tc_u32_pcnt {
|
||||
__u64 rcnt;
|
||||
__u64 rhit;
|
||||
__u64 kcnts[0];
|
||||
};
|
||||
|
||||
/* Flags */
|
||||
|
||||
#define TC_U32_TERMINAL 1
|
||||
#define TC_U32_OFFSET 2
|
||||
#define TC_U32_VAROFFSET 4
|
||||
#define TC_U32_EAT 8
|
||||
|
||||
#define TC_U32_MAXDEPTH 8
|
||||
|
||||
|
||||
/* RSVP filter */
|
||||
|
||||
enum {
|
||||
TCA_RSVP_UNSPEC,
|
||||
TCA_RSVP_CLASSID,
|
||||
TCA_RSVP_DST,
|
||||
TCA_RSVP_SRC,
|
||||
TCA_RSVP_PINFO,
|
||||
TCA_RSVP_POLICE,
|
||||
TCA_RSVP_ACT,
|
||||
__TCA_RSVP_MAX
|
||||
};
|
||||
|
||||
#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
|
||||
|
||||
struct tc_rsvp_gpi {
|
||||
__u32 key;
|
||||
__u32 mask;
|
||||
int offset;
|
||||
};
|
||||
|
||||
struct tc_rsvp_pinfo {
|
||||
struct tc_rsvp_gpi dpi;
|
||||
struct tc_rsvp_gpi spi;
|
||||
__u8 protocol;
|
||||
__u8 tunnelid;
|
||||
__u8 tunnelhdr;
|
||||
__u8 pad;
|
||||
};
|
||||
|
||||
/* ROUTE filter */
|
||||
|
||||
enum {
|
||||
TCA_ROUTE4_UNSPEC,
|
||||
TCA_ROUTE4_CLASSID,
|
||||
TCA_ROUTE4_TO,
|
||||
TCA_ROUTE4_FROM,
|
||||
TCA_ROUTE4_IIF,
|
||||
TCA_ROUTE4_POLICE,
|
||||
TCA_ROUTE4_ACT,
|
||||
__TCA_ROUTE4_MAX
|
||||
};
|
||||
|
||||
#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1)
|
||||
|
||||
|
||||
/* FW filter */
|
||||
|
||||
enum {
|
||||
TCA_FW_UNSPEC,
|
||||
TCA_FW_CLASSID,
|
||||
TCA_FW_POLICE,
|
||||
TCA_FW_INDEV,
|
||||
TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
|
||||
TCA_FW_MASK,
|
||||
__TCA_FW_MAX
|
||||
};
|
||||
|
||||
#define TCA_FW_MAX (__TCA_FW_MAX - 1)
|
||||
|
||||
/* TC index filter */
|
||||
|
||||
enum {
|
||||
TCA_TCINDEX_UNSPEC,
|
||||
TCA_TCINDEX_HASH,
|
||||
TCA_TCINDEX_MASK,
|
||||
TCA_TCINDEX_SHIFT,
|
||||
TCA_TCINDEX_FALL_THROUGH,
|
||||
TCA_TCINDEX_CLASSID,
|
||||
TCA_TCINDEX_POLICE,
|
||||
TCA_TCINDEX_ACT,
|
||||
__TCA_TCINDEX_MAX
|
||||
};
|
||||
|
||||
#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
|
||||
|
||||
/* Flow filter */
|
||||
|
||||
enum {
|
||||
FLOW_KEY_SRC,
|
||||
FLOW_KEY_DST,
|
||||
FLOW_KEY_PROTO,
|
||||
FLOW_KEY_PROTO_SRC,
|
||||
FLOW_KEY_PROTO_DST,
|
||||
FLOW_KEY_IIF,
|
||||
FLOW_KEY_PRIORITY,
|
||||
FLOW_KEY_MARK,
|
||||
FLOW_KEY_NFCT,
|
||||
FLOW_KEY_NFCT_SRC,
|
||||
FLOW_KEY_NFCT_DST,
|
||||
FLOW_KEY_NFCT_PROTO_SRC,
|
||||
FLOW_KEY_NFCT_PROTO_DST,
|
||||
FLOW_KEY_RTCLASSID,
|
||||
FLOW_KEY_SKUID,
|
||||
FLOW_KEY_SKGID,
|
||||
FLOW_KEY_VLAN_TAG,
|
||||
FLOW_KEY_RXHASH,
|
||||
__FLOW_KEY_MAX,
|
||||
};
|
||||
|
||||
#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1)
|
||||
|
||||
enum {
|
||||
FLOW_MODE_MAP,
|
||||
FLOW_MODE_HASH,
|
||||
};
|
||||
|
||||
enum {
|
||||
TCA_FLOW_UNSPEC,
|
||||
TCA_FLOW_KEYS,
|
||||
TCA_FLOW_MODE,
|
||||
TCA_FLOW_BASECLASS,
|
||||
TCA_FLOW_RSHIFT,
|
||||
TCA_FLOW_ADDEND,
|
||||
TCA_FLOW_MASK,
|
||||
TCA_FLOW_XOR,
|
||||
TCA_FLOW_DIVISOR,
|
||||
TCA_FLOW_ACT,
|
||||
TCA_FLOW_POLICE,
|
||||
TCA_FLOW_EMATCHES,
|
||||
TCA_FLOW_PERTURB,
|
||||
__TCA_FLOW_MAX
|
||||
};
|
||||
|
||||
#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1)
|
||||
|
||||
/* Basic filter */
|
||||
|
||||
enum {
|
||||
TCA_BASIC_UNSPEC,
|
||||
TCA_BASIC_CLASSID,
|
||||
TCA_BASIC_EMATCHES,
|
||||
TCA_BASIC_ACT,
|
||||
TCA_BASIC_POLICE,
|
||||
__TCA_BASIC_MAX
|
||||
};
|
||||
|
||||
#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
|
||||
|
||||
|
||||
/* Cgroup classifier */
|
||||
|
||||
enum {
|
||||
TCA_CGROUP_UNSPEC,
|
||||
TCA_CGROUP_ACT,
|
||||
TCA_CGROUP_POLICE,
|
||||
TCA_CGROUP_EMATCHES,
|
||||
__TCA_CGROUP_MAX,
|
||||
};
|
||||
|
||||
#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
|
||||
|
||||
/* BPF classifier */
|
||||
|
||||
#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
|
||||
|
||||
enum {
|
||||
TCA_BPF_UNSPEC,
|
||||
TCA_BPF_ACT,
|
||||
TCA_BPF_POLICE,
|
||||
TCA_BPF_CLASSID,
|
||||
TCA_BPF_OPS_LEN,
|
||||
TCA_BPF_OPS,
|
||||
TCA_BPF_FD,
|
||||
TCA_BPF_NAME,
|
||||
TCA_BPF_FLAGS,
|
||||
TCA_BPF_FLAGS_GEN,
|
||||
TCA_BPF_TAG,
|
||||
TCA_BPF_ID,
|
||||
__TCA_BPF_MAX,
|
||||
};
|
||||
|
||||
#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
|
||||
|
||||
/* Flower classifier */
|
||||
|
||||
enum {
|
||||
TCA_FLOWER_UNSPEC,
|
||||
TCA_FLOWER_CLASSID,
|
||||
TCA_FLOWER_INDEV,
|
||||
TCA_FLOWER_ACT,
|
||||
TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ETH_TYPE, /* be16 */
|
||||
TCA_FLOWER_KEY_IP_PROTO, /* u8 */
|
||||
TCA_FLOWER_KEY_IPV4_SRC, /* be32 */
|
||||
TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */
|
||||
TCA_FLOWER_KEY_IPV4_DST, /* be32 */
|
||||
TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */
|
||||
TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_TCP_SRC, /* be16 */
|
||||
TCA_FLOWER_KEY_TCP_DST, /* be16 */
|
||||
TCA_FLOWER_KEY_UDP_SRC, /* be16 */
|
||||
TCA_FLOWER_KEY_UDP_DST, /* be16 */
|
||||
|
||||
TCA_FLOWER_FLAGS,
|
||||
TCA_FLOWER_KEY_VLAN_ID, /* be16 */
|
||||
TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */
|
||||
TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */
|
||||
TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */
|
||||
TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */
|
||||
TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */
|
||||
TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */
|
||||
TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */
|
||||
TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */
|
||||
TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */
|
||||
|
||||
TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_SCTP_SRC_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_SCTP_DST_MASK, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_SCTP_SRC, /* be16 */
|
||||
TCA_FLOWER_KEY_SCTP_DST, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, /* be16 */
|
||||
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */
|
||||
TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */
|
||||
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_FLAGS, /* be32 */
|
||||
TCA_FLOWER_KEY_FLAGS_MASK, /* be32 */
|
||||
|
||||
TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */
|
||||
TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */
|
||||
|
||||
TCA_FLOWER_KEY_ARP_SIP, /* be32 */
|
||||
TCA_FLOWER_KEY_ARP_SIP_MASK, /* be32 */
|
||||
TCA_FLOWER_KEY_ARP_TIP, /* be32 */
|
||||
TCA_FLOWER_KEY_ARP_TIP_MASK, /* be32 */
|
||||
TCA_FLOWER_KEY_ARP_OP, /* u8 */
|
||||
TCA_FLOWER_KEY_ARP_OP_MASK, /* u8 */
|
||||
TCA_FLOWER_KEY_ARP_SHA, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ARP_SHA_MASK, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ARP_THA, /* ETH_ALEN */
|
||||
TCA_FLOWER_KEY_ARP_THA_MASK, /* ETH_ALEN */
|
||||
|
||||
TCA_FLOWER_KEY_MPLS_TTL, /* u8 - 8 bits */
|
||||
TCA_FLOWER_KEY_MPLS_BOS, /* u8 - 1 bit */
|
||||
TCA_FLOWER_KEY_MPLS_TC, /* u8 - 3 bits */
|
||||
TCA_FLOWER_KEY_MPLS_LABEL, /* be32 - 20 bits */
|
||||
|
||||
TCA_FLOWER_KEY_TCP_FLAGS, /* be16 */
|
||||
TCA_FLOWER_KEY_TCP_FLAGS_MASK, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_IP_TOS, /* u8 */
|
||||
TCA_FLOWER_KEY_IP_TOS_MASK, /* u8 */
|
||||
TCA_FLOWER_KEY_IP_TTL, /* u8 */
|
||||
TCA_FLOWER_KEY_IP_TTL_MASK, /* u8 */
|
||||
|
||||
TCA_FLOWER_KEY_CVLAN_ID, /* be16 */
|
||||
TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */
|
||||
TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */
|
||||
|
||||
TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */
|
||||
TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* u8 */
|
||||
TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */
|
||||
TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */
|
||||
|
||||
TCA_FLOWER_KEY_ENC_OPTS,
|
||||
TCA_FLOWER_KEY_ENC_OPTS_MASK,
|
||||
|
||||
TCA_FLOWER_IN_HW_COUNT,
|
||||
|
||||
__TCA_FLOWER_MAX,
|
||||
};
|
||||
|
||||
#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
|
||||
|
||||
enum {
|
||||
TCA_FLOWER_KEY_ENC_OPTS_UNSPEC,
|
||||
TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested
|
||||
* TCA_FLOWER_KEY_ENC_OPT_GENEVE_
|
||||
* attributes
|
||||
*/
|
||||
__TCA_FLOWER_KEY_ENC_OPTS_MAX,
|
||||
};
|
||||
|
||||
#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1)
|
||||
|
||||
enum {
|
||||
TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC,
|
||||
TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */
|
||||
TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */
|
||||
TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */
|
||||
|
||||
__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
|
||||
};
|
||||
|
||||
#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \
|
||||
(__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
|
||||
|
||||
enum {
|
||||
TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
|
||||
TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
|
||||
};
|
||||
|
||||
/* Match-all classifier */
|
||||
|
||||
enum {
|
||||
TCA_MATCHALL_UNSPEC,
|
||||
TCA_MATCHALL_CLASSID,
|
||||
TCA_MATCHALL_ACT,
|
||||
TCA_MATCHALL_FLAGS,
|
||||
__TCA_MATCHALL_MAX,
|
||||
};
|
||||
|
||||
#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
|
||||
|
||||
/* Extended Matches */
|
||||
|
||||
struct tcf_ematch_tree_hdr {
|
||||
__u16 nmatches;
|
||||
__u16 progid;
|
||||
};
|
||||
|
||||
enum {
|
||||
TCA_EMATCH_TREE_UNSPEC,
|
||||
TCA_EMATCH_TREE_HDR,
|
||||
TCA_EMATCH_TREE_LIST,
|
||||
__TCA_EMATCH_TREE_MAX
|
||||
};
|
||||
#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1)
|
||||
|
||||
struct tcf_ematch_hdr {
|
||||
__u16 matchid;
|
||||
__u16 kind;
|
||||
__u16 flags;
|
||||
__u16 pad; /* currently unused */
|
||||
};
|
||||
|
||||
/* 0 1
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
* +-----------------------+-+-+---+
|
||||
* | Unused |S|I| R |
|
||||
* +-----------------------+-+-+---+
|
||||
*
|
||||
* R(2) ::= relation to next ematch
|
||||
* where: 0 0 END (last ematch)
|
||||
* 0 1 AND
|
||||
* 1 0 OR
|
||||
* 1 1 Unused (invalid)
|
||||
* I(1) ::= invert result
|
||||
* S(1) ::= simple payload
|
||||
*/
|
||||
#define TCF_EM_REL_END 0
|
||||
#define TCF_EM_REL_AND (1<<0)
|
||||
#define TCF_EM_REL_OR (1<<1)
|
||||
#define TCF_EM_INVERT (1<<2)
|
||||
#define TCF_EM_SIMPLE (1<<3)
|
||||
|
||||
#define TCF_EM_REL_MASK 3
|
||||
#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK)
|
||||
|
||||
enum {
|
||||
TCF_LAYER_LINK,
|
||||
TCF_LAYER_NETWORK,
|
||||
TCF_LAYER_TRANSPORT,
|
||||
__TCF_LAYER_MAX
|
||||
};
|
||||
#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
|
||||
|
||||
/* Ematch type assignments
|
||||
* 1..32767 Reserved for ematches inside kernel tree
|
||||
* 32768..65535 Free to use, not reliable
|
||||
*/
|
||||
#define TCF_EM_CONTAINER 0
|
||||
#define TCF_EM_CMP 1
|
||||
#define TCF_EM_NBYTE 2
|
||||
#define TCF_EM_U32 3
|
||||
#define TCF_EM_META 4
|
||||
#define TCF_EM_TEXT 5
|
||||
#define TCF_EM_VLAN 6
|
||||
#define TCF_EM_CANID 7
|
||||
#define TCF_EM_IPSET 8
|
||||
#define TCF_EM_IPT 9
|
||||
#define TCF_EM_MAX 9
|
||||
|
||||
enum {
|
||||
TCF_EM_PROG_TC
|
||||
};
|
||||
|
||||
enum {
|
||||
TCF_EM_OPND_EQ,
|
||||
TCF_EM_OPND_GT,
|
||||
TCF_EM_OPND_LT
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,81 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
|
||||
SANITIZER=${SANITIZER:-address}
|
||||
flags="-O1 -fno-omit-frame-pointer -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER -fsanitize=fuzzer-no-link"
|
||||
|
||||
export CC=${CC:-clang}
|
||||
export CFLAGS=${CFLAGS:-$flags}
|
||||
|
||||
export CXX=${CXX:-clang++}
|
||||
export CXXFLAGS=${CXXFLAGS:-$flags}
|
||||
|
||||
cd "$(dirname -- "$0")/.."
|
||||
|
||||
export OUT=${OUT:-"$(pwd)/out"}
|
||||
mkdir -p "$OUT"
|
||||
|
||||
export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer}
|
||||
|
||||
# libelf is compiled with _FORTIFY_SOURCE by default and it
|
||||
# isn't compatible with MSan. It was borrowed
|
||||
# from https://github.com/google/oss-fuzz/pull/7422
|
||||
if [[ "$SANITIZER" == memory ]]; then
|
||||
CFLAGS+=" -U_FORTIFY_SOURCE"
|
||||
CXXFLAGS+=" -U_FORTIFY_SOURCE"
|
||||
fi
|
||||
|
||||
# The alignment check is turned off by default on OSS-Fuzz/CFLite so it should be
|
||||
# turned on explicitly there. It was borrowed from
|
||||
# https://github.com/google/oss-fuzz/pull/7092
|
||||
if [[ "$SANITIZER" == undefined ]]; then
|
||||
additional_ubsan_checks=alignment
|
||||
UBSAN_FLAGS="-fsanitize=$additional_ubsan_checks -fno-sanitize-recover=$additional_ubsan_checks"
|
||||
CFLAGS+=" $UBSAN_FLAGS"
|
||||
CXXFLAGS+=" $UBSAN_FLAGS"
|
||||
fi
|
||||
|
||||
# Ideally libbelf should be built using release tarballs available
|
||||
# at https://sourceware.org/elfutils/ftp/. Unfortunately sometimes they
|
||||
# fail to compile (for example, elfutils-0.185 fails to compile with LDFLAGS enabled
|
||||
# due to https://bugs.gentoo.org/794601) so let's just point the script to
|
||||
# commits referring to versions of libelf that actually can be built
|
||||
rm -rf elfutils
|
||||
git clone git://sourceware.org/git/elfutils.git
|
||||
(
|
||||
cd elfutils
|
||||
git checkout 83251d4091241acddbdcf16f814e3bc6ef3df49a
|
||||
git log --oneline -1
|
||||
|
||||
# ASan isn't compatible with -Wl,--no-undefined: https://github.com/google/sanitizers/issues/380
|
||||
find -name Makefile.am | xargs sed -i 's/,--no-undefined//'
|
||||
|
||||
# ASan isn't compatible with -Wl,-z,defs either:
|
||||
# https://clang.llvm.org/docs/AddressSanitizer.html#usage
|
||||
sed -i 's/^\(ZDEFS_LDFLAGS=\).*/\1/' configure.ac
|
||||
|
||||
if [[ "$SANITIZER" == undefined ]]; then
|
||||
# That's basicaly what --enable-sanitize-undefined does to turn off unaligned access
|
||||
# elfutils heavily relies on on i386/x86_64 but without changing compiler flags along the way
|
||||
sed -i 's/\(check_undefined_val\)=[0-9]/\1=1/' configure.ac
|
||||
fi
|
||||
|
||||
autoreconf -i -f
|
||||
if ! ./configure --enable-maintainer-mode --disable-debuginfod --disable-libdebuginfod \
|
||||
CC="$CC" CFLAGS="-Wno-error $CFLAGS" CXX="$CXX" CXXFLAGS="-Wno-error $CXXFLAGS" LDFLAGS="$CFLAGS"; then
|
||||
cat config.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make -C config -j$(nproc) V=1
|
||||
make -C lib -j$(nproc) V=1
|
||||
make -C libelf -j$(nproc) V=1
|
||||
)
|
||||
|
||||
make -C src BUILD_STATIC_ONLY=y V=1 clean
|
||||
make -C src -j$(nproc) CFLAGS="-I$(pwd)/elfutils/libelf $CFLAGS" BUILD_STATIC_ONLY=y V=1
|
||||
|
||||
$CC $CFLAGS -Isrc -Iinclude -Iinclude/uapi -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -c fuzz/bpf-object-fuzzer.c -o bpf-object-fuzzer.o
|
||||
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE bpf-object-fuzzer.o src/libbpf.a "$(pwd)/elfutils/libelf/libelf.a" -l:libz.a -o "$OUT/bpf-object-fuzzer"
|
||||
|
||||
cp fuzz/bpf-object-fuzzer_seed_corpus.zip "$OUT"
|
||||
18
scripts/check-reallocarray.sh
Executable file
18
scripts/check-reallocarray.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
tfile=$(mktemp /tmp/test_reallocarray_XXXXXXXX.c)
|
||||
ofile=${tfile%.c}.o
|
||||
|
||||
cat > $tfile <<EOL
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return !!reallocarray(NULL, 1, 1);
|
||||
}
|
||||
EOL
|
||||
|
||||
gcc $tfile -o $ofile >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then echo "FAIL"; fi
|
||||
/bin/rm -f $tfile $ofile
|
||||
@@ -6,6 +6,7 @@ usage () {
|
||||
echo "Set BPF_NEXT_BASELINE to override bpf-next tree commit, otherwise read from <libbpf-repo>/CHECKPOINT-COMMIT."
|
||||
echo "Set BPF_BASELINE to override bpf tree commit, otherwise read from <libbpf-repo>/BPF-CHECKPOINT-COMMIT."
|
||||
echo "Set MANUAL_MODE to 1 to manually control every cherry-picked commits."
|
||||
echo "Set IGNORE_CONSISTENCY to 1 to ignore failed contents consistency check."
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -17,7 +18,7 @@ BPF_BRANCH=${3-""}
|
||||
BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||
BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
|
||||
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ]; then
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ] || [ -z "${BPF_BRANCH}" ]; then
|
||||
echo "Error: libbpf or linux repos are not specified"
|
||||
usage
|
||||
fi
|
||||
@@ -45,16 +46,12 @@ PATH_MAP=( \
|
||||
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||
[tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
|
||||
[tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
|
||||
[include/uapi/linux/perf_event.h]=include/uapi/linux/perf_event.h \
|
||||
[Documentation/bpf/libbpf]=docs \
|
||||
[tools/include/tools/libc_compat.h]=include/tools/libc_compat.h \
|
||||
)
|
||||
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore"
|
||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
|
||||
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$'
|
||||
|
||||
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
||||
for p in "${!PATH_MAP[@]}"; do
|
||||
@@ -75,7 +72,7 @@ commit_desc()
|
||||
}
|
||||
|
||||
# Create commit single-line signature, which consists of:
|
||||
# - full commit subject
|
||||
# - full commit hash
|
||||
# - author date in ISO8601 format
|
||||
# - full commit body with newlines replaced with vertical bars (|)
|
||||
# - shortstat appended at the end
|
||||
@@ -140,7 +137,6 @@ cherry_pick_commits()
|
||||
echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
|
||||
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
|
||||
conflict_cnt=$(git diff --name-only | wc -l)
|
||||
prompt_resolution=1
|
||||
|
||||
if ((${libbpf_conflict_cnt} == 0)); then
|
||||
echo "Looks like only non-libbpf files have conflicts, ignoring..."
|
||||
@@ -156,37 +152,15 @@ cherry_pick_commits()
|
||||
echo "Error! That still failed! Please resolve manually."
|
||||
else
|
||||
echo "Success! All cherry-pick conflicts were resolved for '${desc}'!"
|
||||
prompt_resolution=0
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if ((${prompt_resolution} == 1)); then
|
||||
read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
|
||||
fi
|
||||
read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
|
||||
fi
|
||||
# Append signature of just cherry-picked commit to avoid
|
||||
# potentially cherry-picking the same commit twice later when
|
||||
# processing bpf tree commits. At this point we don't know yet
|
||||
# the final commit sha in libbpf repo, so we record Linux SHA
|
||||
# instead as LINUX_<sha>.
|
||||
echo LINUX_$(git log --pretty='%h' -n1) "${signature}" >> ${TMP_DIR}/libbpf_commits.txt
|
||||
done
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
echo "Cleaning up..."
|
||||
rm -r ${TMP_DIR}
|
||||
cd_to ${LINUX_REPO}
|
||||
git checkout ${TIP_SYM_REF}
|
||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
|
||||
${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG} || true
|
||||
|
||||
cd_to .
|
||||
echo "DONE."
|
||||
}
|
||||
|
||||
|
||||
cd_to ${LIBBPF_REPO}
|
||||
GITHUB_ABS_DIR=$(pwd)
|
||||
echo "Dumping existing libbpf commit signatures..."
|
||||
@@ -252,7 +226,6 @@ FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --prune-empty -f --subdirector
|
||||
COMMIT_CNT=$(git rev-list --count ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG})
|
||||
if ((${COMMIT_CNT} <= 0)); then
|
||||
echo "No new changes to apply, we are done!"
|
||||
cleanup
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -264,21 +237,18 @@ cd_to ${LIBBPF_REPO}
|
||||
git checkout -b ${LIBBPF_SYNC_TAG}
|
||||
|
||||
for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
||||
if ! git am -3 --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||
if ! patch -p1 --merge < "${TMP_DIR}/patches/${patch}"; then
|
||||
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||
fi
|
||||
git am --continue
|
||||
if ! git am --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||
fi
|
||||
done
|
||||
|
||||
# Generate bpf_helper_defs.h and commit, if anything changed
|
||||
# restore Linux tip to use bpf_doc.py
|
||||
# restore Linux tip to use bpf_helpers_doc.py
|
||||
cd_to ${LINUX_REPO}
|
||||
git checkout ${TIP_TAG}
|
||||
# re-generate bpf_helper_defs.h
|
||||
cd_to ${LIBBPF_REPO}
|
||||
"${LINUX_ABS_DIR}/scripts/bpf_doc.py" --header \
|
||||
"${LINUX_ABS_DIR}/scripts/bpf_helpers_doc.py" --header \
|
||||
--file include/uapi/linux/bpf.h > src/bpf_helper_defs.h
|
||||
# if anything changed, commit it
|
||||
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
||||
@@ -316,7 +286,7 @@ cd_to ${LINUX_REPO}
|
||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LINUX_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/linux-view.ls
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
||||
|
||||
cd_to ${LIBBPF_REPO}
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
||||
@@ -334,17 +304,19 @@ done
|
||||
if ((${CONSISTENT} == 1)); then
|
||||
echo "Great! Content is identical!"
|
||||
else
|
||||
ignore_inconsistency=n
|
||||
echo "Unfortunately, there are some inconsistencies, please double check."
|
||||
read -p "Does everything look good? [y/N]: " ignore_inconsistency
|
||||
case "${ignore_inconsistency}" in
|
||||
"y" | "Y")
|
||||
echo "Ok, proceeding..."
|
||||
;;
|
||||
*)
|
||||
echo "Oops, exiting with error..."
|
||||
exit 4
|
||||
esac
|
||||
echo "Unfortunately, there are consistency problems!"
|
||||
if ((${IGNORE_CONSISTENCY-0} != 1)); then
|
||||
exit 4
|
||||
fi
|
||||
fi
|
||||
|
||||
cleanup
|
||||
echo "Cleaning up..."
|
||||
rm -r ${TMP_DIR}
|
||||
cd_to ${LINUX_REPO}
|
||||
git checkout ${TIP_SYM_REF}
|
||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
|
||||
${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
||||
|
||||
cd_to .
|
||||
echo "DONE."
|
||||
|
||||
|
||||
114
src/Makefile
114
src/Makefile
@@ -1,39 +1,31 @@
|
||||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
ifeq ($(V),1)
|
||||
Q =
|
||||
msg =
|
||||
else
|
||||
Q = @
|
||||
msg = @printf ' %-8s %s%s\n' "$(1)" "$(2)" "$(if $(3), $(3))";
|
||||
endif
|
||||
|
||||
LIBBPF_MAJOR_VERSION := 0
|
||||
LIBBPF_MINOR_VERSION := 8
|
||||
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
|
||||
LIBBPF_MAP_VERSION := $(shell grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | sort -rV | head -n1 | cut -d'_' -f2)
|
||||
ifneq ($(LIBBPF_MAJMIN_VERSION), $(LIBBPF_MAP_VERSION))
|
||||
$(error Libbpf release ($(LIBBPF_VERSION)) and map ($(LIBBPF_MAP_VERSION)) versions are out of sync!)
|
||||
endif
|
||||
LIBBPF_VERSION := $(shell \
|
||||
grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | \
|
||||
sort -rV | head -n1 | cut -d'_' -f2)
|
||||
LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
|
||||
|
||||
TOPDIR = ..
|
||||
|
||||
INCLUDES := -I. -I$(TOPDIR)/include -I$(TOPDIR)/include/uapi
|
||||
ALL_CFLAGS := $(INCLUDES)
|
||||
|
||||
FEATURE_REALLOCARRAY := $(shell $(TOPDIR)/scripts/check-reallocarray.sh)
|
||||
ifneq ($(FEATURE_REALLOCARRAY),)
|
||||
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||
endif
|
||||
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
|
||||
CFLAGS ?= -g -O2 -Werror -Wall
|
||||
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
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)
|
||||
ALL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libelf)
|
||||
ALL_LDFLAGS += $(shell $(PKG_CONFIG) --libs libelf)
|
||||
endif
|
||||
|
||||
OBJDIR ?= .
|
||||
@@ -41,8 +33,7 @@ SHARED_OBJDIR := $(OBJDIR)/sharedobjs
|
||||
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
||||
btf_dump.o hashmap.o ringbuf.o strset.o linker.o gen_loader.o \
|
||||
relo_core.o usdt.o
|
||||
btf_dump.o hashmap.o ringbuf.o
|
||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||
|
||||
@@ -54,10 +45,9 @@ ifndef BUILD_STATIC_ONLY
|
||||
VERSION_SCRIPT := libbpf.map
|
||||
endif
|
||||
|
||||
HEADERS := bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h xsk.h \
|
||||
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h \
|
||||
bpf_helpers.h bpf_helper_defs.h bpf_tracing.h \
|
||||
bpf_endian.h bpf_core_read.h skel_internal.h libbpf_version.h \
|
||||
usdt.bpf.h
|
||||
bpf_endian.h bpf_core_read.h libbpf_common.h
|
||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
||||
bpf.h bpf_common.h btf.h)
|
||||
|
||||
@@ -67,19 +57,12 @@ INSTALL = install
|
||||
|
||||
DESTDIR ?=
|
||||
|
||||
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(shell uname -m)),)
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
LIBSUBDIR := lib64
|
||||
else
|
||||
LIBSUBDIR := lib
|
||||
endif
|
||||
|
||||
# By default let the pc file itself use ${prefix} in includedir/libdir so that
|
||||
# the prefix can be overridden at runtime (eg: --define-prefix)
|
||||
ifndef LIBDIR
|
||||
LIBDIR_PC := $$\{prefix\}/$(LIBSUBDIR)
|
||||
else
|
||||
LIBDIR_PC := $(LIBDIR)
|
||||
endif
|
||||
PREFIX ?= /usr
|
||||
LIBDIR ?= $(PREFIX)/$(LIBSUBDIR)
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
@@ -90,54 +73,50 @@ TAGS_PROG := $(if $(shell which etags 2>/dev/null),etags,ctags)
|
||||
all: $(STATIC_LIBS) $(SHARED_LIBS) $(PC_FILE)
|
||||
|
||||
$(OBJDIR)/libbpf.a: $(STATIC_OBJS)
|
||||
$(call msg,AR,$@)
|
||||
$(Q)$(AR) rcs $@ $^
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION)
|
||||
$(Q)ln -sf $(^F) $@
|
||||
ln -sf $(^F) $@
|
||||
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||
$(Q)ln -sf $(^F) $@
|
||||
ln -sf $(^F) $@
|
||||
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
|
||||
$(call msg,CC,$@)
|
||||
$(Q)$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||
$^ $(ALL_LDFLAGS) -o $@
|
||||
$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||
$^ $(ALL_LDFLAGS) -o $@
|
||||
|
||||
$(OBJDIR)/libbpf.pc: force
|
||||
$(Q)sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||
-e "s|@LIBDIR@|$(LIBDIR_PC)|" \
|
||||
$(OBJDIR)/libbpf.pc:
|
||||
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||
-e "s|@LIBDIR@|$(LIBDIR)|" \
|
||||
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
||||
< libbpf.pc.template > $@
|
||||
|
||||
$(STATIC_OBJDIR) $(SHARED_OBJDIR):
|
||||
$(call msg,MKDIR,$@)
|
||||
$(Q)mkdir -p $@
|
||||
$(STATIC_OBJDIR):
|
||||
mkdir -p $(STATIC_OBJDIR)
|
||||
|
||||
$(SHARED_OBJDIR):
|
||||
mkdir -p $(SHARED_OBJDIR)
|
||||
|
||||
$(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
|
||||
$(call msg,CC,$@)
|
||||
$(Q)$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
$(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
|
||||
$(call msg,CC,$@)
|
||||
$(Q)$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
define do_install
|
||||
$(call msg,INSTALL,$1)
|
||||
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||
if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||
fi;
|
||||
$(Q)$(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR)$2'
|
||||
fi; \
|
||||
$(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR)$2'
|
||||
endef
|
||||
|
||||
# Preserve symlinks at installation.
|
||||
define do_s_install
|
||||
$(call msg,INSTALL,$1)
|
||||
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||
if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||
fi;
|
||||
$(Q)cp -fR $1 '$(DESTDIR)$2'
|
||||
fi; \
|
||||
cp -fpR $1 '$(DESTDIR)$2'
|
||||
endef
|
||||
|
||||
install: all install_headers install_pkgconfig
|
||||
@@ -155,18 +134,13 @@ install_pkgconfig: $(PC_FILE)
|
||||
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
||||
|
||||
clean:
|
||||
$(call msg,CLEAN)
|
||||
$(Q)rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
|
||||
rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
|
||||
|
||||
.PHONY: cscope tags force
|
||||
.PHONY: cscope tags
|
||||
cscope:
|
||||
$(call msg,CSCOPE)
|
||||
$(Q)ls *.c *.h > cscope.files
|
||||
$(Q)cscope -b -q -f cscope.out
|
||||
ls *.c *.h > cscope.files
|
||||
cscope -b -q -f cscope.out
|
||||
|
||||
tags:
|
||||
$(call msg,CTAGS)
|
||||
$(Q)rm -f TAGS tags
|
||||
$(Q)ls *.c *.h | xargs $(TAGS_PROG) -a
|
||||
|
||||
force:
|
||||
rm -f TAGS tags
|
||||
ls *.c *.h | xargs $(TAGS_PROG) -a
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
API naming convention
|
||||
=====================
|
||||
libbpf API naming convention
|
||||
============================
|
||||
|
||||
libbpf API provides access to a few logically separated groups of
|
||||
functions and types. Every group has its own naming convention
|
||||
@@ -10,14 +10,14 @@ new function or type is added to keep libbpf API clean and consistent.
|
||||
|
||||
All types and functions provided by libbpf API should have one of the
|
||||
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
|
||||
``btf_dump_``, ``ring_buffer_``, ``perf_buffer_``.
|
||||
``perf_buffer_``.
|
||||
|
||||
System call wrappers
|
||||
--------------------
|
||||
|
||||
System call wrappers are simple wrappers for commands supported by
|
||||
sys_bpf system call. These wrappers should go to ``bpf.h`` header file
|
||||
and map one to one to corresponding commands.
|
||||
and map one-on-one to corresponding commands.
|
||||
|
||||
For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
|
||||
command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
|
||||
@@ -49,6 +49,10 @@ object, ``bpf_object``, double underscore and ``open`` that defines the
|
||||
purpose of the function to open ELF file and create ``bpf_object`` from
|
||||
it.
|
||||
|
||||
Another example: ``bpf_program__load`` is named for corresponding
|
||||
object, ``bpf_program``, that is separated from other part of the name
|
||||
by double underscore.
|
||||
|
||||
All objects and corresponding functions other than BTF related should go
|
||||
to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
|
||||
|
||||
@@ -68,8 +72,12 @@ of both low-level ring access functions and high-level configuration
|
||||
functions. These can be mixed and matched. Note that these functions
|
||||
are not reentrant for performance reasons.
|
||||
|
||||
ABI
|
||||
---
|
||||
Please take a look at Documentation/networking/af_xdp.rst in the Linux
|
||||
kernel source tree on how to use XDP sockets and for some common
|
||||
mistakes in case you do not get any traffic up to user space.
|
||||
|
||||
libbpf ABI
|
||||
==========
|
||||
|
||||
libbpf can be both linked statically or used as DSO. To avoid possible
|
||||
conflicts with other libraries an application is linked with, all
|
||||
@@ -108,8 +116,7 @@ This bump in ABI version is at most once per kernel development cycle.
|
||||
|
||||
For example, if current state of ``libbpf.map`` is:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
.. code-block::
|
||||
LIBBPF_0.0.1 {
|
||||
global:
|
||||
bpf_func_a;
|
||||
@@ -121,8 +128,7 @@ For example, if current state of ``libbpf.map`` is:
|
||||
, and a new symbol ``bpf_func_c`` is being introduced, then
|
||||
``libbpf.map`` should be changed like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
.. code-block::
|
||||
LIBBPF_0.0.1 {
|
||||
global:
|
||||
bpf_func_a;
|
||||
@@ -142,7 +148,7 @@ Format of version script and ways to handle ABI changes, including
|
||||
incompatible ones, described in details in [1].
|
||||
|
||||
Stand-alone build
|
||||
-------------------
|
||||
=================
|
||||
|
||||
Under https://github.com/libbpf/libbpf there is a (semi-)automated
|
||||
mirror of the mainline's version of libbpf for a stand-alone build.
|
||||
@@ -150,53 +156,13 @@ mirror of the mainline's version of libbpf for a stand-alone build.
|
||||
However, all changes to libbpf's code base must be upstreamed through
|
||||
the mainline kernel tree.
|
||||
|
||||
|
||||
API documentation convention
|
||||
============================
|
||||
|
||||
The libbpf API is documented via comments above definitions in
|
||||
header files. These comments can be rendered by doxygen and sphinx
|
||||
for well organized html output. This section describes the
|
||||
convention in which these comments should be formated.
|
||||
|
||||
Here is an example from btf.h:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/**
|
||||
* @brief **btf__new()** creates a new instance of a BTF object from the raw
|
||||
* bytes of an ELF's BTF section
|
||||
* @param data raw bytes
|
||||
* @param size number of bytes passed in `data`
|
||||
* @return new BTF object instance which has to be eventually freed with
|
||||
* **btf__free()**
|
||||
*
|
||||
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
|
||||
* error code from such a pointer `libbpf_get_error()` should be used. If
|
||||
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
|
||||
* returned on error instead. In both cases thread-local `errno` variable is
|
||||
* always set to error code as well.
|
||||
*/
|
||||
|
||||
The comment must start with a block comment of the form '/\*\*'.
|
||||
|
||||
The documentation always starts with a @brief directive. This line is a short
|
||||
description about this API. It starts with the name of the API, denoted in bold
|
||||
like so: **api_name**. Please include an open and close parenthesis if this is a
|
||||
function. Follow with the short description of the API. A longer form description
|
||||
can be added below the last directive, at the bottom of the comment.
|
||||
|
||||
Parameters are denoted with the @param directive, there should be one for each
|
||||
parameter. If this is a function with a non-void return, use the @return directive
|
||||
to document it.
|
||||
|
||||
License
|
||||
-------------------
|
||||
=======
|
||||
|
||||
libbpf is dual-licensed under LGPL 2.1 and BSD 2-Clause.
|
||||
|
||||
Links
|
||||
-------------------
|
||||
=====
|
||||
|
||||
[1] https://www.akkadia.org/drepper/dsohowto.pdf
|
||||
(Chapter 3. Maintaining APIs and ABIs).
|
||||
317
src/bpf.h
317
src/bpf.h
@@ -29,38 +29,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libbpf_common.h"
|
||||
#include "libbpf_legacy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int libbpf_set_memlock_rlim(size_t memlock_bytes);
|
||||
|
||||
struct bpf_map_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
__u32 btf_fd;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
__u32 btf_vmlinux_value_type_id;
|
||||
|
||||
__u32 inner_map_fd;
|
||||
__u32 map_flags;
|
||||
__u64 map_extra;
|
||||
|
||||
__u32 numa_node;
|
||||
__u32 map_ifindex;
|
||||
};
|
||||
#define bpf_map_create_opts__last_field map_ifindex
|
||||
|
||||
LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
__u32 key_size,
|
||||
__u32 value_size,
|
||||
__u32 max_entries,
|
||||
const struct bpf_map_create_opts *opts);
|
||||
|
||||
struct bpf_create_map_attr {
|
||||
const char *name;
|
||||
enum bpf_map_type map_type;
|
||||
@@ -79,95 +52,25 @@ struct bpf_create_map_attr {
|
||||
};
|
||||
};
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int
|
||||
bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);
|
||||
LIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size,
|
||||
int max_entries, __u32 map_flags, int node);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size,
|
||||
int max_entries, __u32 map_flags);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size,
|
||||
int value_size, int max_entries, __u32 map_flags);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type,
|
||||
const char *name, int key_size,
|
||||
int inner_map_fd, int max_entries,
|
||||
__u32 map_flags, int node);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type,
|
||||
const char *name, int key_size,
|
||||
int inner_map_fd, int max_entries,
|
||||
__u32 map_flags);
|
||||
|
||||
struct bpf_prog_load_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
/* libbpf can retry BPF_PROG_LOAD command if bpf() syscall returns
|
||||
* -EAGAIN. This field determines how many attempts libbpf has to
|
||||
* make. If not specified, libbpf will use default value of 5.
|
||||
*/
|
||||
int attempts;
|
||||
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
__u32 prog_btf_fd;
|
||||
__u32 prog_flags;
|
||||
__u32 prog_ifindex;
|
||||
__u32 kern_version;
|
||||
|
||||
__u32 attach_btf_id;
|
||||
__u32 attach_prog_fd;
|
||||
__u32 attach_btf_obj_fd;
|
||||
|
||||
const int *fd_array;
|
||||
|
||||
/* .BTF.ext func info data */
|
||||
const void *func_info;
|
||||
__u32 func_info_cnt;
|
||||
__u32 func_info_rec_size;
|
||||
|
||||
/* .BTF.ext line info data */
|
||||
const void *line_info;
|
||||
__u32 line_info_cnt;
|
||||
__u32 line_info_rec_size;
|
||||
|
||||
/* verifier log options */
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
char *log_buf;
|
||||
};
|
||||
#define bpf_prog_load_opts__last_field log_buf
|
||||
|
||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
const struct bpf_prog_load_opts *opts);
|
||||
/* this "specialization" should go away in libbpf 1.0 */
|
||||
LIBBPF_API int bpf_prog_load_v0_6_0(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
const struct bpf_prog_load_opts *opts);
|
||||
|
||||
/* This is an elaborate way to not conflict with deprecated bpf_prog_load()
|
||||
* API, defined in libbpf.h. Once we hit libbpf 1.0, all this will be gone.
|
||||
* With this approach, if someone is calling bpf_prog_load() with
|
||||
* 4 arguments, they will use the deprecated API, which keeps backwards
|
||||
* compatibility (both source code and binary). If bpf_prog_load() is called
|
||||
* with 6 arguments, though, it gets redirected to __bpf_prog_load.
|
||||
* So looking forward to libbpf 1.0 when this hack will be gone and
|
||||
* __bpf_prog_load() will be called just bpf_prog_load().
|
||||
*/
|
||||
#ifndef bpf_prog_load
|
||||
#define bpf_prog_load(...) ___libbpf_overload(___bpf_prog_load, __VA_ARGS__)
|
||||
#define ___bpf_prog_load4(file, type, pobj, prog_fd) \
|
||||
bpf_prog_load_deprecated(file, type, pobj, prog_fd)
|
||||
#define ___bpf_prog_load6(prog_type, prog_name, license, insns, insn_cnt, opts) \
|
||||
bpf_prog_load(prog_type, prog_name, license, insns, insn_cnt, opts)
|
||||
#endif /* bpf_prog_load */
|
||||
|
||||
struct bpf_load_program_attr {
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
@@ -197,18 +100,15 @@ struct bpf_load_program_attr {
|
||||
/* Flags to direct loading requirements */
|
||||
#define MAPS_RELAX_COMPAT 0x01
|
||||
|
||||
/* Recommended log buffer size */
|
||||
/* Recommend log buffer size */
|
||||
#define BPF_LOG_BUF_SIZE (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int
|
||||
bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
|
||||
const struct bpf_insn *insns, size_t insns_cnt,
|
||||
const char *license, __u32 kern_version,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
|
||||
const struct bpf_insn *insns,
|
||||
size_t insns_cnt, __u32 prog_flags,
|
||||
@@ -216,23 +116,6 @@ LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
|
||||
char *log_buf, size_t log_buf_sz,
|
||||
int log_level);
|
||||
|
||||
struct bpf_btf_load_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
/* kernel log options */
|
||||
char *log_buf;
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
};
|
||||
#define bpf_btf_load_opts__last_field log_size
|
||||
|
||||
LIBBPF_API int bpf_btf_load(const void *btf_data, size_t btf_size,
|
||||
const struct bpf_btf_load_opts *opts);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 8, "use bpf_btf_load() instead")
|
||||
LIBBPF_API int bpf_load_btf(const void *btf, __u32 btf_size, char *log_buf,
|
||||
__u32 log_buf_size, bool do_log);
|
||||
|
||||
LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||
__u64 flags);
|
||||
|
||||
@@ -241,10 +124,7 @@ LIBBPF_API int bpf_map_lookup_elem_flags(int fd, const void *key, void *value,
|
||||
__u64 flags);
|
||||
LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
|
||||
void *value);
|
||||
LIBBPF_API int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key,
|
||||
void *value, __u64 flags);
|
||||
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
|
||||
LIBBPF_API int bpf_map_delete_elem_flags(int fd, const void *key, __u64 flags);
|
||||
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
||||
LIBBPF_API int bpf_map_freeze(int fd);
|
||||
|
||||
@@ -255,128 +135,17 @@ struct bpf_map_batch_opts {
|
||||
};
|
||||
#define bpf_map_batch_opts__last_field flags
|
||||
|
||||
|
||||
/**
|
||||
* @brief **bpf_map_delete_batch()** allows for batch deletion of multiple
|
||||
* elements in a BPF map.
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param keys pointer to an array of *count* keys
|
||||
* @param count input and output parameter; on input **count** represents the
|
||||
* number of elements in the map to delete in batch;
|
||||
* on output if a non-EFAULT error is returned, **count** represents the number of deleted
|
||||
* elements if the output **count** value is not equal to the input **count** value
|
||||
* If EFAULT is returned, **count** should not be trusted to be correct.
|
||||
* @param opts options for configuring the way the batch deletion works
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_map_delete_batch(int fd, const void *keys,
|
||||
LIBBPF_API int bpf_map_delete_batch(int fd, void *keys,
|
||||
__u32 *count,
|
||||
const struct bpf_map_batch_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map_lookup_batch()** allows for batch lookup of BPF map elements.
|
||||
*
|
||||
* The parameter *in_batch* is the address of the first element in the batch to read.
|
||||
* *out_batch* is an output parameter that should be passed as *in_batch* to subsequent
|
||||
* calls to **bpf_map_lookup_batch()**. NULL can be passed for *in_batch* to indicate
|
||||
* that the batched lookup starts from the beginning of the map.
|
||||
*
|
||||
* The *keys* and *values* are output parameters which must point to memory large enough to
|
||||
* hold *count* items based on the key and value size of the map *map_fd*. The *keys*
|
||||
* buffer must be of *key_size* * *count*. The *values* buffer must be of
|
||||
* *value_size* * *count*.
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param in_batch address of the first element in batch to read, can pass NULL to
|
||||
* indicate that the batched lookup starts from the beginning of the map.
|
||||
* @param out_batch output parameter that should be passed to next call as *in_batch*
|
||||
* @param keys pointer to an array large enough for *count* keys
|
||||
* @param values pointer to an array large enough for *count* values
|
||||
* @param count input and output parameter; on input it's the number of elements
|
||||
* in the map to read in batch; on output it's the number of elements that were
|
||||
* successfully read.
|
||||
* If a non-EFAULT error is returned, count will be set as the number of elements
|
||||
* that were read before the error occurred.
|
||||
* If EFAULT is returned, **count** should not be trusted to be correct.
|
||||
* @param opts options for configuring the way the batch lookup works
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch,
|
||||
void *keys, void *values, __u32 *count,
|
||||
const struct bpf_map_batch_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map_lookup_and_delete_batch()** allows for batch lookup and deletion
|
||||
* of BPF map elements where each element is deleted after being retrieved.
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param in_batch address of the first element in batch to read, can pass NULL to
|
||||
* get address of the first element in *out_batch*
|
||||
* @param out_batch output parameter that should be passed to next call as *in_batch*
|
||||
* @param keys pointer to an array of *count* keys
|
||||
* @param values pointer to an array large enough for *count* values
|
||||
* @param count input and output parameter; on input it's the number of elements
|
||||
* in the map to read and delete in batch; on output it represents the number of
|
||||
* elements that were successfully read and deleted
|
||||
* If a non-**EFAULT** error code is returned and if the output **count** value
|
||||
* is not equal to the input **count** value, up to **count** elements may
|
||||
* have been deleted.
|
||||
* if **EFAULT** is returned up to *count* elements may have been deleted without
|
||||
* being returned via the *keys* and *values* output parameters.
|
||||
* @param opts options for configuring the way the batch lookup and delete works
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_map_lookup_and_delete_batch(int fd, void *in_batch,
|
||||
void *out_batch, void *keys,
|
||||
void *values, __u32 *count,
|
||||
const struct bpf_map_batch_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief **bpf_map_update_batch()** updates multiple elements in a map
|
||||
* by specifying keys and their corresponding values.
|
||||
*
|
||||
* The *keys* and *values* parameters must point to memory large enough
|
||||
* to hold *count* items based on the key and value size of the map.
|
||||
*
|
||||
* The *opts* parameter can be used to control how *bpf_map_update_batch()*
|
||||
* should handle keys that either do or do not already exist in the map.
|
||||
* In particular the *flags* parameter of *bpf_map_batch_opts* can be
|
||||
* one of the following:
|
||||
*
|
||||
* Note that *count* is an input and output parameter, where on output it
|
||||
* represents how many elements were successfully updated. Also note that if
|
||||
* **EFAULT** then *count* should not be trusted to be correct.
|
||||
*
|
||||
* **BPF_ANY**
|
||||
* Create new elements or update existing.
|
||||
*
|
||||
* **BPF_NOEXIST**
|
||||
* Create new elements only if they do not exist.
|
||||
*
|
||||
* **BPF_EXIST**
|
||||
* Update existing elements.
|
||||
*
|
||||
* **BPF_F_LOCK**
|
||||
* Update spin_lock-ed map elements. This must be
|
||||
* specified if the map value contains a spinlock.
|
||||
*
|
||||
* @param fd BPF map file descriptor
|
||||
* @param keys pointer to an array of *count* keys
|
||||
* @param values pointer to an array of *count* values
|
||||
* @param count input and output parameter; on input it's the number of elements
|
||||
* in the map to update in batch; on output if a non-EFAULT error is returned,
|
||||
* **count** represents the number of updated elements if the output **count**
|
||||
* value is not equal to the input **count** value.
|
||||
* If EFAULT is returned, **count** should not be trusted to be correct.
|
||||
* @param opts options for configuring the way the batch update works
|
||||
* @return 0, on success; negative error code, otherwise (errno is also set to
|
||||
* the error code)
|
||||
*/
|
||||
LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values,
|
||||
LIBBPF_API int bpf_map_update_batch(int fd, void *keys, void *values,
|
||||
__u32 *count,
|
||||
const struct bpf_map_batch_opts *opts);
|
||||
|
||||
@@ -392,10 +161,6 @@ struct bpf_prog_attach_opts {
|
||||
|
||||
LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type, unsigned int flags);
|
||||
LIBBPF_API int bpf_prog_attach_opts(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 8, "use bpf_prog_attach_opts() instead")
|
||||
LIBBPF_API int bpf_prog_attach_xattr(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type,
|
||||
const struct bpf_prog_attach_opts *opts);
|
||||
@@ -403,38 +168,15 @@ LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
union bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */
|
||||
struct bpf_link_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
union bpf_iter_link_info *iter_info;
|
||||
__u32 iter_info_len;
|
||||
__u32 target_btf_id;
|
||||
union {
|
||||
struct {
|
||||
__u64 bpf_cookie;
|
||||
} perf_event;
|
||||
struct {
|
||||
__u32 flags;
|
||||
__u32 cnt;
|
||||
const char **syms;
|
||||
const unsigned long *addrs;
|
||||
const __u64 *cookies;
|
||||
} kprobe_multi;
|
||||
struct {
|
||||
__u64 cookie;
|
||||
} tracing;
|
||||
};
|
||||
size_t :0;
|
||||
};
|
||||
#define bpf_link_create_opts__last_field kprobe_multi.cookies
|
||||
#define bpf_link_create_opts__last_field sz
|
||||
|
||||
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type,
|
||||
const struct bpf_link_create_opts *opts);
|
||||
|
||||
LIBBPF_API int bpf_link_detach(int link_fd);
|
||||
|
||||
struct bpf_link_update_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags; /* extra flags */
|
||||
@@ -464,14 +206,12 @@ struct bpf_prog_test_run_attr {
|
||||
* out: length of cxt_out */
|
||||
};
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_test_run_opts() instead")
|
||||
LIBBPF_API int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr);
|
||||
|
||||
/*
|
||||
* bpf_prog_test_run does not check that data_out is large enough. Consider
|
||||
* using bpf_prog_test_run_opts instead.
|
||||
* using bpf_prog_test_run_xattr instead.
|
||||
*/
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_test_run_opts() instead")
|
||||
LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
||||
__u32 size, void *data_out, __u32 *size_out,
|
||||
__u32 *retval, __u32 *duration);
|
||||
@@ -488,6 +228,8 @@ LIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type,
|
||||
__u32 query_flags, __u32 *attach_flags,
|
||||
__u32 *prog_ids, __u32 *prog_cnt);
|
||||
LIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd);
|
||||
LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf,
|
||||
__u32 log_buf_size, bool do_log);
|
||||
LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
|
||||
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
|
||||
__u64 *probe_offset, __u64 *probe_addr);
|
||||
@@ -495,41 +237,6 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
|
||||
enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */
|
||||
LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);
|
||||
|
||||
struct bpf_prog_bind_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags;
|
||||
};
|
||||
#define bpf_prog_bind_opts__last_field flags
|
||||
|
||||
LIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd,
|
||||
const struct bpf_prog_bind_opts *opts);
|
||||
|
||||
struct bpf_test_run_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
const void *data_in; /* optional */
|
||||
void *data_out; /* optional */
|
||||
__u32 data_size_in;
|
||||
__u32 data_size_out; /* in: max length of data_out
|
||||
* out: length of data_out
|
||||
*/
|
||||
const void *ctx_in; /* optional */
|
||||
void *ctx_out; /* optional */
|
||||
__u32 ctx_size_in;
|
||||
__u32 ctx_size_out; /* in: max length of ctx_out
|
||||
* out: length of cxt_out
|
||||
*/
|
||||
__u32 retval; /* out: return code of the BPF program */
|
||||
int repeat;
|
||||
__u32 duration; /* out: average per repetition in ns */
|
||||
__u32 flags;
|
||||
__u32 cpu;
|
||||
__u32 batch_size;
|
||||
};
|
||||
#define bpf_test_run_opts__last_field batch_size
|
||||
|
||||
LIBBPF_API int bpf_prog_test_run_opts(int prog_fd,
|
||||
struct bpf_test_run_opts *opts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -19,52 +19,32 @@ enum bpf_field_info_kind {
|
||||
BPF_FIELD_RSHIFT_U64 = 5,
|
||||
};
|
||||
|
||||
/* second argument to __builtin_btf_type_id() built-in */
|
||||
enum bpf_type_id_kind {
|
||||
BPF_TYPE_ID_LOCAL = 0, /* BTF type ID in local program */
|
||||
BPF_TYPE_ID_TARGET = 1, /* BTF type ID in target kernel */
|
||||
};
|
||||
|
||||
/* second argument to __builtin_preserve_type_info() built-in */
|
||||
enum bpf_type_info_kind {
|
||||
BPF_TYPE_EXISTS = 0, /* type existence in target kernel */
|
||||
BPF_TYPE_SIZE = 1, /* type size in target kernel */
|
||||
};
|
||||
|
||||
/* second argument to __builtin_preserve_enum_value() built-in */
|
||||
enum bpf_enum_value_kind {
|
||||
BPF_ENUMVAL_EXISTS = 0, /* enum value existence in kernel */
|
||||
BPF_ENUMVAL_VALUE = 1, /* enum value value relocation */
|
||||
};
|
||||
|
||||
#define __CORE_RELO(src, field, info) \
|
||||
__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||
bpf_probe_read_kernel( \
|
||||
(void *)dst, \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
bpf_probe_read((void *)dst, \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
#else
|
||||
/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so
|
||||
* for big-endian we need to adjust destination pointer accordingly, based on
|
||||
* field byte size
|
||||
*/
|
||||
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||
bpf_probe_read_kernel( \
|
||||
(void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
bpf_probe_read((void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \
|
||||
__CORE_RELO(src, fld, BYTE_SIZE), \
|
||||
(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Extract bitfield, identified by s->field, and return its value as u64.
|
||||
* All this is done in relocatable manner, so bitfield changes such as
|
||||
* signedness, bit size, offset changes, this will be handled automatically.
|
||||
* This version of macro is using bpf_probe_read_kernel() to read underlying
|
||||
* integer storage. Macro functions as an expression and its return type is
|
||||
* bpf_probe_read_kernel()'s return value: 0, on success, <0 on error.
|
||||
* This version of macro is using bpf_probe_read() to read underlying integer
|
||||
* storage. Macro functions as an expression and its return type is
|
||||
* bpf_probe_read()'s return value: 0, on success, <0 on error.
|
||||
*/
|
||||
#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({ \
|
||||
unsigned long long val = 0; \
|
||||
@@ -88,19 +68,11 @@ enum bpf_enum_value_kind {
|
||||
const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
||||
unsigned long long val; \
|
||||
\
|
||||
/* This is a so-called barrier_var() operation that makes specified \
|
||||
* variable "a black box" for optimizing compiler. \
|
||||
* It forces compiler to perform BYTE_OFFSET relocation on p and use \
|
||||
* its calculated value in the switch below, instead of applying \
|
||||
* the same relocation 4 times for each individual memory load. \
|
||||
*/ \
|
||||
asm volatile("" : "=r"(p) : "0"(p)); \
|
||||
\
|
||||
switch (__CORE_RELO(s, field, BYTE_SIZE)) { \
|
||||
case 1: val = *(const unsigned char *)p; break; \
|
||||
case 2: val = *(const unsigned short *)p; break; \
|
||||
case 4: val = *(const unsigned int *)p; break; \
|
||||
case 8: val = *(const unsigned long long *)p; break; \
|
||||
case 1: val = *(const unsigned char *)p; \
|
||||
case 2: val = *(const unsigned short *)p; \
|
||||
case 4: val = *(const unsigned int *)p; \
|
||||
case 8: val = *(const unsigned long long *)p; \
|
||||
} \
|
||||
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
||||
if (__CORE_RELO(s, field, SIGNED)) \
|
||||
@@ -110,114 +82,25 @@ enum bpf_enum_value_kind {
|
||||
val; \
|
||||
})
|
||||
|
||||
#define ___bpf_field_ref1(field) (field)
|
||||
#define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field)
|
||||
#define ___bpf_field_ref(args...) \
|
||||
___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that field actually exists in target kernel's.
|
||||
* Returns:
|
||||
* 1, if matching field is present in target kernel;
|
||||
* 0, if no matching field found.
|
||||
*
|
||||
* Supports two forms:
|
||||
* - field reference through variable access:
|
||||
* bpf_core_field_exists(p->my_field);
|
||||
* - field reference through type and field names:
|
||||
* bpf_core_field_exists(struct my_type, my_field).
|
||||
*/
|
||||
#define bpf_core_field_exists(field...) \
|
||||
__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_EXISTS)
|
||||
#define bpf_core_field_exists(field) \
|
||||
__builtin_preserve_field_info(field, BPF_FIELD_EXISTS)
|
||||
|
||||
/*
|
||||
* Convenience macro to get the byte size of a field. Works for integers,
|
||||
* Convenience macro to get byte size of a field. Works for integers,
|
||||
* struct/unions, pointers, arrays, and enums.
|
||||
*
|
||||
* Supports two forms:
|
||||
* - field reference through variable access:
|
||||
* bpf_core_field_size(p->my_field);
|
||||
* - field reference through type and field names:
|
||||
* bpf_core_field_size(struct my_type, my_field).
|
||||
*/
|
||||
#define bpf_core_field_size(field...) \
|
||||
__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_SIZE)
|
||||
#define bpf_core_field_size(field) \
|
||||
__builtin_preserve_field_info(field, BPF_FIELD_BYTE_SIZE)
|
||||
|
||||
/*
|
||||
* Convenience macro to get field's byte offset.
|
||||
*
|
||||
* Supports two forms:
|
||||
* - field reference through variable access:
|
||||
* bpf_core_field_offset(p->my_field);
|
||||
* - field reference through type and field names:
|
||||
* bpf_core_field_offset(struct my_type, my_field).
|
||||
*/
|
||||
#define bpf_core_field_offset(field...) \
|
||||
__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_OFFSET)
|
||||
|
||||
/*
|
||||
* Convenience macro to get BTF type ID of a specified type, using a local BTF
|
||||
* information. Return 32-bit unsigned integer with type ID from program's own
|
||||
* BTF. Always succeeds.
|
||||
*/
|
||||
#define bpf_core_type_id_local(type) \
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)
|
||||
|
||||
/*
|
||||
* Convenience macro to get BTF type ID of a target kernel's type that matches
|
||||
* specified local type.
|
||||
* Returns:
|
||||
* - valid 32-bit unsigned type ID in kernel BTF;
|
||||
* - 0, if no matching type was found in a target kernel BTF.
|
||||
*/
|
||||
#define bpf_core_type_id_kernel(type) \
|
||||
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided named type
|
||||
* (struct/union/enum/typedef) exists in a target kernel.
|
||||
* Returns:
|
||||
* 1, if such type is present in target kernel's BTF;
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_exists(type) \
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
|
||||
|
||||
/*
|
||||
* Convenience macro to get the byte size of a provided named type
|
||||
* (struct/union/enum/typedef) in a target kernel.
|
||||
* Returns:
|
||||
* >= 0 size (in bytes), if type is present in target kernel's BTF;
|
||||
* 0, if no matching type is found.
|
||||
*/
|
||||
#define bpf_core_type_size(type) \
|
||||
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)
|
||||
|
||||
/*
|
||||
* Convenience macro to check that provided enumerator value is defined in
|
||||
* a target kernel.
|
||||
* Returns:
|
||||
* 1, if specified enum type and its enumerator value are present in target
|
||||
* kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#define bpf_core_enum_value_exists(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)
|
||||
|
||||
/*
|
||||
* Convenience macro to get the integer value of an enumerator value in
|
||||
* a target kernel.
|
||||
* Returns:
|
||||
* 64-bit value, if specified enum type and its enumerator value are
|
||||
* present in target kernel's BTF;
|
||||
* 0, if no matching enum and/or enum value within that enum is found.
|
||||
*/
|
||||
#define bpf_core_enum_value(enum_type, enum_value) \
|
||||
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)
|
||||
|
||||
/*
|
||||
* bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures
|
||||
* offset relocation for source address using __builtin_preserve_access_index()
|
||||
* bpf_core_read() abstracts away bpf_probe_read() call and captures offset
|
||||
* relocation for source address using __builtin_preserve_access_index()
|
||||
* built-in, provided by Clang.
|
||||
*
|
||||
* __builtin_preserve_access_index() takes as an argument an expression of
|
||||
@@ -232,22 +115,17 @@ enum bpf_enum_value_kind {
|
||||
* (local) BTF, used to record relocation.
|
||||
*/
|
||||
#define bpf_core_read(dst, sz, src) \
|
||||
bpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
bpf_probe_read(dst, sz, \
|
||||
(const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */
|
||||
#define bpf_core_read_user(dst, sz, src) \
|
||||
bpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
/*
|
||||
* bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()
|
||||
* additionally emitting BPF CO-RE field relocation for specified source
|
||||
* argument.
|
||||
*/
|
||||
#define bpf_core_read_str(dst, sz, src) \
|
||||
bpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */
|
||||
#define bpf_core_read_user_str(dst, sz, src) \
|
||||
bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||
bpf_probe_read_str(dst, sz, \
|
||||
(const void *)__builtin_preserve_access_index(src))
|
||||
|
||||
#define ___concat(a, b) a ## b
|
||||
#define ___apply(fn, n) ___concat(fn, n)
|
||||
@@ -306,29 +184,30 @@ enum bpf_enum_value_kind {
|
||||
read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
|
||||
|
||||
/* "recursively" read a sequence of inner pointers using local __t var */
|
||||
#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a);
|
||||
#define ___rd_last(fn, ...) \
|
||||
___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
|
||||
#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__)
|
||||
#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||
#define ___read_ptrs(fn, src, ...) \
|
||||
___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__)
|
||||
#define ___rd_first(src, a) ___read(bpf_core_read, &__t, ___type(src), src, a);
|
||||
#define ___rd_last(...) \
|
||||
___read(bpf_core_read, &__t, \
|
||||
___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
|
||||
#define ___rd_p1(...) const void *__t; ___rd_first(__VA_ARGS__)
|
||||
#define ___rd_p2(...) ___rd_p1(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p3(...) ___rd_p2(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p4(...) ___rd_p3(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p5(...) ___rd_p4(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p6(...) ___rd_p5(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p7(...) ___rd_p6(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p8(...) ___rd_p7(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___rd_p9(...) ___rd_p8(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
||||
#define ___read_ptrs(src, ...) \
|
||||
___apply(___rd_p, ___narg(__VA_ARGS__))(src, __VA_ARGS__)
|
||||
|
||||
#define ___core_read0(fn, fn_ptr, dst, src, a) \
|
||||
#define ___core_read0(fn, dst, src, a) \
|
||||
___read(fn, dst, ___type(src), src, a);
|
||||
#define ___core_readN(fn, fn_ptr, dst, src, ...) \
|
||||
___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__)) \
|
||||
#define ___core_readN(fn, dst, src, ...) \
|
||||
___read_ptrs(src, ___nolast(__VA_ARGS__)) \
|
||||
___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \
|
||||
___last(__VA_ARGS__));
|
||||
#define ___core_read(fn, fn_ptr, dst, src, a, ...) \
|
||||
___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst, \
|
||||
#define ___core_read(fn, dst, src, a, ...) \
|
||||
___apply(___core_read, ___empty(__VA_ARGS__))(fn, dst, \
|
||||
src, a, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
@@ -336,73 +215,20 @@ enum bpf_enum_value_kind {
|
||||
* BPF_CORE_READ(), in which final field is read into user-provided storage.
|
||||
* See BPF_CORE_READ() below for more details on general usage.
|
||||
*/
|
||||
#define BPF_CORE_READ_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_core_read, bpf_core_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/*
|
||||
* Variant of BPF_CORE_READ_INTO() for reading from user-space memory.
|
||||
*
|
||||
* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.
|
||||
*/
|
||||
#define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_core_read_user, bpf_core_read_user, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ_INTO() */
|
||||
#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read, bpf_probe_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ_USER_INTO().
|
||||
*
|
||||
* As no CO-RE relocations are emitted, source types can be arbitrary and are
|
||||
* not restricted to kernel types only.
|
||||
*/
|
||||
#define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read_user, bpf_probe_read_user, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
#define BPF_CORE_READ_INTO(dst, src, a, ...) \
|
||||
({ \
|
||||
___core_read(bpf_core_read, dst, src, a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/*
|
||||
* BPF_CORE_READ_STR_INTO() does same "pointer chasing" as
|
||||
* BPF_CORE_READ() for intermediate pointers, but then executes (and returns
|
||||
* corresponding error code) bpf_core_read_str() for final string read.
|
||||
*/
|
||||
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_core_read_str, bpf_core_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/*
|
||||
* Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory.
|
||||
*
|
||||
* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.
|
||||
*/
|
||||
#define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_core_read_user_str, bpf_core_read_user, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */
|
||||
#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read_str, bpf_probe_read, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/*
|
||||
* Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO().
|
||||
*
|
||||
* As no CO-RE relocations are emitted, source types can be arbitrary and are
|
||||
* not restricted to kernel types only.
|
||||
*/
|
||||
#define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({ \
|
||||
___core_read(bpf_probe_read_user_str, bpf_probe_read_user, \
|
||||
dst, (src), a, ##__VA_ARGS__) \
|
||||
})
|
||||
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \
|
||||
({ \
|
||||
___core_read(bpf_core_read_str, dst, src, a, ##__VA_ARGS__) \
|
||||
})
|
||||
|
||||
/*
|
||||
* BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially
|
||||
@@ -413,61 +239,25 @@ enum bpf_enum_value_kind {
|
||||
* int x = BPF_CORE_READ(s, a.b.c, d.e, f, g);
|
||||
*
|
||||
* BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF
|
||||
* CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically
|
||||
* equivalent to:
|
||||
* CO-RE relocatable bpf_probe_read() wrapper) calls, logically equivalent to:
|
||||
* 1. const void *__t = s->a.b.c;
|
||||
* 2. __t = __t->d.e;
|
||||
* 3. __t = __t->f;
|
||||
* 4. return __t->g;
|
||||
*
|
||||
* Equivalence is logical, because there is a heavy type casting/preservation
|
||||
* involved, as well as all the reads are happening through
|
||||
* bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to
|
||||
* emit CO-RE relocations.
|
||||
* involved, as well as all the reads are happening through bpf_probe_read()
|
||||
* calls using __builtin_preserve_access_index() to emit CO-RE relocations.
|
||||
*
|
||||
* N.B. Only up to 9 "field accessors" are supported, which should be more
|
||||
* than enough for any practical purpose.
|
||||
*/
|
||||
#define BPF_CORE_READ(src, a, ...) ({ \
|
||||
___type((src), a, ##__VA_ARGS__) __r; \
|
||||
BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
||||
__r; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Variant of BPF_CORE_READ() for reading from user-space memory.
|
||||
*
|
||||
* NOTE: all the source types involved are still *kernel types* and need to
|
||||
* exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will
|
||||
* fail. Custom user types are not relocatable with CO-RE.
|
||||
* The typical situation in which BPF_CORE_READ_USER() might be used is to
|
||||
* read kernel UAPI types from the user-space memory passed in as a syscall
|
||||
* input argument.
|
||||
*/
|
||||
#define BPF_CORE_READ_USER(src, a, ...) ({ \
|
||||
___type((src), a, ##__VA_ARGS__) __r; \
|
||||
BPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
||||
__r; \
|
||||
})
|
||||
|
||||
/* Non-CO-RE variant of BPF_CORE_READ() */
|
||||
#define BPF_PROBE_READ(src, a, ...) ({ \
|
||||
___type((src), a, ##__VA_ARGS__) __r; \
|
||||
BPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
||||
__r; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Non-CO-RE variant of BPF_CORE_READ_USER().
|
||||
*
|
||||
* As no CO-RE relocations are emitted, source types can be arbitrary and are
|
||||
* not restricted to kernel types only.
|
||||
*/
|
||||
#define BPF_PROBE_READ_USER(src, a, ...) ({ \
|
||||
___type((src), a, ##__VA_ARGS__) __r; \
|
||||
BPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
||||
__r; \
|
||||
})
|
||||
#define BPF_CORE_READ(src, a, ...) \
|
||||
({ \
|
||||
___type(src, a, ##__VA_ARGS__) __r; \
|
||||
BPF_CORE_READ_INTO(&__r, src, a, ##__VA_ARGS__); \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,35 +2,8 @@
|
||||
#ifndef __BPF_ENDIAN__
|
||||
#define __BPF_ENDIAN__
|
||||
|
||||
/*
|
||||
* Isolate byte #n and put it into byte #m, for __u##b type.
|
||||
* E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
|
||||
* 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
|
||||
* 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
|
||||
* 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
|
||||
* 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
|
||||
*/
|
||||
#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
|
||||
|
||||
#define ___bpf_swab16(x) ((__u16)( \
|
||||
___bpf_mvb(x, 16, 0, 1) | \
|
||||
___bpf_mvb(x, 16, 1, 0)))
|
||||
|
||||
#define ___bpf_swab32(x) ((__u32)( \
|
||||
___bpf_mvb(x, 32, 0, 3) | \
|
||||
___bpf_mvb(x, 32, 1, 2) | \
|
||||
___bpf_mvb(x, 32, 2, 1) | \
|
||||
___bpf_mvb(x, 32, 3, 0)))
|
||||
|
||||
#define ___bpf_swab64(x) ((__u64)( \
|
||||
___bpf_mvb(x, 64, 0, 7) | \
|
||||
___bpf_mvb(x, 64, 1, 6) | \
|
||||
___bpf_mvb(x, 64, 2, 5) | \
|
||||
___bpf_mvb(x, 64, 3, 4) | \
|
||||
___bpf_mvb(x, 64, 4, 3) | \
|
||||
___bpf_mvb(x, 64, 5, 2) | \
|
||||
___bpf_mvb(x, 64, 6, 1) | \
|
||||
___bpf_mvb(x, 64, 7, 0)))
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/swab.h>
|
||||
|
||||
/* LLVM's BPF target selects the endianness of the CPU
|
||||
* it compiles on, or the user specifies (bpfel/bpfeb),
|
||||
@@ -50,16 +23,16 @@
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define __bpf_ntohs(x) __builtin_bswap16(x)
|
||||
# define __bpf_htons(x) __builtin_bswap16(x)
|
||||
# define __bpf_constant_ntohs(x) ___bpf_swab16(x)
|
||||
# define __bpf_constant_htons(x) ___bpf_swab16(x)
|
||||
# define __bpf_constant_ntohs(x) ___constant_swab16(x)
|
||||
# define __bpf_constant_htons(x) ___constant_swab16(x)
|
||||
# define __bpf_ntohl(x) __builtin_bswap32(x)
|
||||
# define __bpf_htonl(x) __builtin_bswap32(x)
|
||||
# define __bpf_constant_ntohl(x) ___bpf_swab32(x)
|
||||
# define __bpf_constant_htonl(x) ___bpf_swab32(x)
|
||||
# define __bpf_constant_ntohl(x) ___constant_swab32(x)
|
||||
# define __bpf_constant_htonl(x) ___constant_swab32(x)
|
||||
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
|
||||
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
|
||||
# define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
|
||||
# define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
|
||||
# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x)
|
||||
# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x)
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define __bpf_ntohs(x) (x)
|
||||
# define __bpf_htons(x) (x)
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
#ifndef __BPF_GEN_INTERNAL_H
|
||||
#define __BPF_GEN_INTERNAL_H
|
||||
|
||||
#include "bpf.h"
|
||||
|
||||
struct ksym_relo_desc {
|
||||
const char *name;
|
||||
int kind;
|
||||
int insn_idx;
|
||||
bool is_weak;
|
||||
bool is_typeless;
|
||||
};
|
||||
|
||||
struct ksym_desc {
|
||||
const char *name;
|
||||
int ref;
|
||||
int kind;
|
||||
union {
|
||||
/* used for kfunc */
|
||||
int off;
|
||||
/* used for typeless ksym */
|
||||
bool typeless;
|
||||
};
|
||||
int insn;
|
||||
};
|
||||
|
||||
struct bpf_gen {
|
||||
struct gen_loader_opts *opts;
|
||||
void *data_start;
|
||||
void *data_cur;
|
||||
void *insn_start;
|
||||
void *insn_cur;
|
||||
ssize_t cleanup_label;
|
||||
__u32 nr_progs;
|
||||
__u32 nr_maps;
|
||||
int log_level;
|
||||
int error;
|
||||
struct ksym_relo_desc *relos;
|
||||
int relo_cnt;
|
||||
struct bpf_core_relo *core_relos;
|
||||
int core_relo_cnt;
|
||||
char attach_target[128];
|
||||
int attach_kind;
|
||||
struct ksym_desc *ksyms;
|
||||
__u32 nr_ksyms;
|
||||
int fd_array;
|
||||
int nr_fd_array;
|
||||
};
|
||||
|
||||
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps);
|
||||
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps);
|
||||
void bpf_gen__free(struct bpf_gen *gen);
|
||||
void bpf_gen__load_btf(struct bpf_gen *gen, const void *raw_data, __u32 raw_size);
|
||||
void bpf_gen__map_create(struct bpf_gen *gen,
|
||||
enum bpf_map_type map_type, const char *map_name,
|
||||
__u32 key_size, __u32 value_size, __u32 max_entries,
|
||||
struct bpf_map_create_opts *map_attr, int map_idx);
|
||||
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);
|
||||
void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *value, __u32 value_size);
|
||||
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
|
||||
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
bool is_typeless, int kind, int insn_idx);
|
||||
void bpf_gen__record_relo_core(struct bpf_gen *gen, const struct bpf_core_relo *core_relo);
|
||||
void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int key, int inner_map_idx);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,58 +14,33 @@
|
||||
#define __type(name, val) typeof(val) *name
|
||||
#define __array(name, val) typeof(val) *name[]
|
||||
|
||||
/* Helper macro to print out debug messages */
|
||||
#define bpf_printk(fmt, ...) \
|
||||
({ \
|
||||
char ____fmt[] = fmt; \
|
||||
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/*
|
||||
* Helper macro to place programs, maps, license in
|
||||
* different sections in elf_bpf file. Section names
|
||||
* are interpreted by libbpf depending on the context (BPF programs, BPF maps,
|
||||
* extern variables, etc).
|
||||
* To allow use of SEC() with externs (e.g., for extern .maps declarations),
|
||||
* make sure __attribute__((unused)) doesn't trigger compilation warning.
|
||||
* are interpreted by elf_bpf loader
|
||||
*/
|
||||
#define SEC(name) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
|
||||
__attribute__((section(name), used)) \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
#define SEC(NAME) __attribute__((section(NAME), used))
|
||||
|
||||
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
|
||||
#undef __always_inline
|
||||
#define __always_inline inline __attribute__((always_inline))
|
||||
|
||||
#ifndef __noinline
|
||||
#define __noinline __attribute__((noinline))
|
||||
#ifndef __always_inline
|
||||
#define __always_inline __attribute__((always_inline))
|
||||
#endif
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use __hidden attribute to mark a non-static BPF subprogram effectively
|
||||
* static for BPF verifier's verification algorithm purposes, allowing more
|
||||
* extensive and permissive BPF verification process, taking into account
|
||||
* subprogram's caller context.
|
||||
*/
|
||||
#define __hidden __attribute__((visibility("hidden")))
|
||||
|
||||
/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include
|
||||
* any system-level headers (such as stddef.h, linux/version.h, etc), and
|
||||
* commonly-used macros like NULL and KERNEL_VERSION aren't available through
|
||||
* vmlinux.h. This just adds unnecessary hurdles and forces users to re-define
|
||||
* them on their own. So as a convenience, provide such definitions here.
|
||||
*/
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#ifndef KERNEL_VERSION
|
||||
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macros to manipulate data structures
|
||||
* Helper macro to manipulate data structures
|
||||
*/
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
||||
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
@@ -75,78 +50,6 @@
|
||||
})
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler (optimization) barrier.
|
||||
*/
|
||||
#ifndef barrier
|
||||
#define barrier() asm volatile("" ::: "memory")
|
||||
#endif
|
||||
|
||||
/* Variable-specific compiler (optimization) barrier. It's a no-op which makes
|
||||
* compiler believe that there is some black box modification of a given
|
||||
* variable and thus prevents compiler from making extra assumption about its
|
||||
* value and potential simplifications and optimizations on this variable.
|
||||
*
|
||||
* E.g., compiler might often delay or even omit 32-bit to 64-bit casting of
|
||||
* a variable, making some code patterns unverifiable. Putting barrier_var()
|
||||
* in place will ensure that cast is performed before the barrier_var()
|
||||
* invocation, because compiler has to pessimistically assume that embedded
|
||||
* asm section might perform some extra operations on that variable.
|
||||
*
|
||||
* This is a variable-specific variant of more global barrier().
|
||||
*/
|
||||
#ifndef barrier_var
|
||||
#define barrier_var(var) asm volatile("" : "=r"(var) : "0"(var))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro to throw a compilation error if __bpf_unreachable() gets
|
||||
* built into the resulting code. This works given BPF back end does not
|
||||
* implement __builtin_trap(). This is useful to assert that certain paths
|
||||
* of the program code are never used and hence eliminated by the compiler.
|
||||
*
|
||||
* For example, consider a switch statement that covers known cases used by
|
||||
* the program. __bpf_unreachable() can then reside in the default case. If
|
||||
* the program gets extended such that a case is not covered in the switch
|
||||
* statement, then it will throw a build error due to the default case not
|
||||
* being compiled out.
|
||||
*/
|
||||
#ifndef __bpf_unreachable
|
||||
# define __bpf_unreachable() __builtin_trap()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper function to perform a tail call with a constant/immediate map slot.
|
||||
*/
|
||||
#if __clang_major__ >= 8 && defined(__bpf__)
|
||||
static __always_inline void
|
||||
bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
|
||||
{
|
||||
if (!__builtin_constant_p(slot))
|
||||
__bpf_unreachable();
|
||||
|
||||
/*
|
||||
* Provide a hard guarantee that LLVM won't optimize setting r2 (map
|
||||
* pointer) and r3 (constant map index) from _different paths_ ending
|
||||
* up at the _same_ call insn as otherwise we won't be able to use the
|
||||
* jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
|
||||
* given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
|
||||
* tracking for prog array pokes") for details on verifier tracking.
|
||||
*
|
||||
* Note on clobber list: we need to stay in-line with BPF calling
|
||||
* convention, so even if we don't end up using r0, r4, r5, we need
|
||||
* to mark them as clobber so that LLVM doesn't end up using them
|
||||
* before / after the call.
|
||||
*/
|
||||
asm volatile("r1 = %[ctx]\n\t"
|
||||
"r2 = %[map]\n\t"
|
||||
"r3 = %[slot]\n\t"
|
||||
"call 12"
|
||||
:: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper structure used by eBPF C program
|
||||
* to describe BPF map attributes to libbpf loader
|
||||
@@ -157,7 +60,7 @@ struct bpf_map_def {
|
||||
unsigned int value_size;
|
||||
unsigned int max_entries;
|
||||
unsigned int map_flags;
|
||||
} __attribute__((deprecated("use BTF-defined maps in .maps section")));
|
||||
};
|
||||
|
||||
enum libbpf_pin_type {
|
||||
LIBBPF_PIN_NONE,
|
||||
@@ -172,117 +75,5 @@ enum libbpf_tristate {
|
||||
};
|
||||
|
||||
#define __kconfig __attribute__((section(".kconfig")))
|
||||
#define __ksym __attribute__((section(".ksyms")))
|
||||
#define __kptr __attribute__((btf_type_tag("kptr")))
|
||||
#define __kptr_ref __attribute__((btf_type_tag("kptr_ref")))
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#endif
|
||||
#ifndef ___bpf_apply
|
||||
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
|
||||
#endif
|
||||
#ifndef ___bpf_nth
|
||||
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
|
||||
#endif
|
||||
#ifndef ___bpf_narg
|
||||
#define ___bpf_narg(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#endif
|
||||
|
||||
#define ___bpf_fill0(arr, p, x) do {} while (0)
|
||||
#define ___bpf_fill1(arr, p, x) arr[p] = x
|
||||
#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)
|
||||
#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)
|
||||
#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)
|
||||
#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)
|
||||
#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)
|
||||
#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)
|
||||
#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)
|
||||
#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)
|
||||
#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)
|
||||
#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)
|
||||
#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)
|
||||
#define ___bpf_fill(arr, args...) \
|
||||
___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)
|
||||
|
||||
/*
|
||||
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
|
||||
* in a structure.
|
||||
*/
|
||||
#define BPF_SEQ_PRINTF(seq, fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
/*
|
||||
* BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
|
||||
* an array of u64.
|
||||
*/
|
||||
#define BPF_SNPRINTF(out, out_size, fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_snprintf(out, out_size, ___fmt, \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
#ifdef BPF_NO_GLOBAL_DATA
|
||||
#define BPF_PRINTK_FMT_MOD
|
||||
#else
|
||||
#define BPF_PRINTK_FMT_MOD static const
|
||||
#endif
|
||||
|
||||
#define __bpf_printk(fmt, ...) \
|
||||
({ \
|
||||
BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \
|
||||
bpf_trace_printk(____fmt, sizeof(____fmt), \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
/*
|
||||
* __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
|
||||
* instead of an array of u64.
|
||||
*/
|
||||
#define __bpf_vprintk(fmt, args...) \
|
||||
({ \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[___bpf_narg(args)]; \
|
||||
\
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
___bpf_fill(___param, args); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
\
|
||||
bpf_trace_vprintk(___fmt, sizeof(___fmt), \
|
||||
___param, sizeof(___param)); \
|
||||
})
|
||||
|
||||
/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args
|
||||
* Otherwise use __bpf_vprintk
|
||||
*/
|
||||
#define ___bpf_pick_printk(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
|
||||
__bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
|
||||
__bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\
|
||||
__bpf_printk /*1*/, __bpf_printk /*0*/)
|
||||
|
||||
/* Helper macro to print out debug messages */
|
||||
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
struct bpf_prog_linfo {
|
||||
void *raw_linfo;
|
||||
void *raw_jited_linfo;
|
||||
@@ -106,7 +109,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
||||
nr_linfo = info->nr_line_info;
|
||||
|
||||
if (!nr_linfo)
|
||||
return errno = EINVAL, NULL;
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* The min size that bpf_prog_linfo has to access for
|
||||
@@ -114,11 +117,11 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
||||
*/
|
||||
if (info->line_info_rec_size <
|
||||
offsetof(struct bpf_line_info, file_name_off))
|
||||
return errno = EINVAL, NULL;
|
||||
return NULL;
|
||||
|
||||
prog_linfo = calloc(1, sizeof(*prog_linfo));
|
||||
if (!prog_linfo)
|
||||
return errno = ENOMEM, NULL;
|
||||
return NULL;
|
||||
|
||||
/* Copy xlated line_info */
|
||||
prog_linfo->nr_linfo = nr_linfo;
|
||||
@@ -174,7 +177,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
||||
|
||||
err_free:
|
||||
bpf_prog_linfo__free(prog_linfo);
|
||||
return errno = EINVAL, NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct bpf_line_info *
|
||||
@@ -186,11 +189,11 @@ bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
||||
const __u64 *jited_linfo;
|
||||
|
||||
if (func_idx >= prog_linfo->nr_jited_func)
|
||||
return errno = ENOENT, NULL;
|
||||
return NULL;
|
||||
|
||||
nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
|
||||
if (nr_skip >= nr_linfo)
|
||||
return errno = ENOENT, NULL;
|
||||
return NULL;
|
||||
|
||||
start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
|
||||
jited_rec_size = prog_linfo->jited_rec_size;
|
||||
@@ -198,7 +201,7 @@ bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
||||
(start * jited_rec_size);
|
||||
jited_linfo = raw_jited_linfo;
|
||||
if (addr < *jited_linfo)
|
||||
return errno = ENOENT, NULL;
|
||||
return NULL;
|
||||
|
||||
nr_linfo -= nr_skip;
|
||||
rec_size = prog_linfo->rec_size;
|
||||
@@ -225,13 +228,13 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
|
||||
|
||||
nr_linfo = prog_linfo->nr_linfo;
|
||||
if (nr_skip >= nr_linfo)
|
||||
return errno = ENOENT, NULL;
|
||||
return NULL;
|
||||
|
||||
rec_size = prog_linfo->rec_size;
|
||||
raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
|
||||
linfo = raw_linfo;
|
||||
if (insn_off < linfo->insn_off)
|
||||
return errno = ENOENT, NULL;
|
||||
return NULL;
|
||||
|
||||
nr_linfo -= nr_skip;
|
||||
for (i = 0; i < nr_linfo; i++) {
|
||||
|
||||
@@ -24,388 +24,300 @@
|
||||
#elif defined(__TARGET_ARCH_sparc)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_riscv)
|
||||
#define bpf_target_riscv
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_arc)
|
||||
#define bpf_target_arc
|
||||
#define bpf_target_defined
|
||||
#else
|
||||
|
||||
/* Fall back to what the compiler says */
|
||||
#if defined(__x86_64__)
|
||||
#define bpf_target_x86
|
||||
#define bpf_target_defined
|
||||
#elif defined(__s390__)
|
||||
#define bpf_target_s390
|
||||
#define bpf_target_defined
|
||||
#elif defined(__arm__)
|
||||
#define bpf_target_arm
|
||||
#define bpf_target_defined
|
||||
#elif defined(__aarch64__)
|
||||
#define bpf_target_arm64
|
||||
#define bpf_target_defined
|
||||
#elif defined(__mips__)
|
||||
#define bpf_target_mips
|
||||
#define bpf_target_defined
|
||||
#elif defined(__powerpc__)
|
||||
#define bpf_target_powerpc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__sparc__)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define bpf_target_riscv
|
||||
#define bpf_target_defined
|
||||
#elif defined(__arc__)
|
||||
#define bpf_target_arc
|
||||
#define bpf_target_defined
|
||||
#endif /* no compiler target */
|
||||
|
||||
#undef bpf_target_defined
|
||||
#endif
|
||||
|
||||
#ifndef __BPF_TARGET_MISSING
|
||||
#define __BPF_TARGET_MISSING "GCC error \"Must specify a BPF target arch via __TARGET_ARCH_xxx\""
|
||||
/* Fall back to what the compiler says */
|
||||
#ifndef bpf_target_defined
|
||||
#if defined(__x86_64__)
|
||||
#define bpf_target_x86
|
||||
#elif defined(__s390__)
|
||||
#define bpf_target_s390
|
||||
#elif defined(__arm__)
|
||||
#define bpf_target_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define bpf_target_arm64
|
||||
#elif defined(__mips__)
|
||||
#define bpf_target_mips
|
||||
#elif defined(__powerpc__)
|
||||
#define bpf_target_powerpc
|
||||
#elif defined(__sparc__)
|
||||
#define bpf_target_sparc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
#if defined(__KERNEL__) || defined(__VMLINUX_H__)
|
||||
|
||||
#define __PT_PARM1_REG di
|
||||
#define __PT_PARM2_REG si
|
||||
#define __PT_PARM3_REG dx
|
||||
#define __PT_PARM4_REG cx
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_RET_REG sp
|
||||
#define __PT_FP_REG bp
|
||||
#define __PT_RC_REG ax
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG ip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
#define PT_REGS_PARM1(x) ((x)->di)
|
||||
#define PT_REGS_PARM2(x) ((x)->si)
|
||||
#define PT_REGS_PARM3(x) ((x)->dx)
|
||||
#define PT_REGS_PARM4(x) ((x)->cx)
|
||||
#define PT_REGS_PARM5(x) ((x)->r8)
|
||||
#define PT_REGS_RET(x) ((x)->sp)
|
||||
#define PT_REGS_FP(x) ((x)->bp)
|
||||
#define PT_REGS_RC(x) ((x)->ax)
|
||||
#define PT_REGS_SP(x) ((x)->sp)
|
||||
#define PT_REGS_IP(x) ((x)->ip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), di)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), si)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), dx)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), cx)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), bp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), ax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), ip)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#define __PT_PARM1_REG eax
|
||||
#define __PT_PARM2_REG edx
|
||||
#define __PT_PARM3_REG ecx
|
||||
/* i386 kernel is built with -mregparm=3 */
|
||||
#define __PT_PARM4_REG __unsupported__
|
||||
#define __PT_PARM5_REG __unsupported__
|
||||
#define __PT_RET_REG esp
|
||||
#define __PT_FP_REG ebp
|
||||
#define __PT_RC_REG eax
|
||||
#define __PT_SP_REG esp
|
||||
#define __PT_IP_REG eip
|
||||
#define PT_REGS_PARM1(x) ((x)->eax)
|
||||
#define PT_REGS_PARM2(x) ((x)->edx)
|
||||
#define PT_REGS_PARM3(x) ((x)->ecx)
|
||||
#define PT_REGS_PARM4(x) 0
|
||||
#define PT_REGS_PARM5(x) 0
|
||||
#define PT_REGS_RET(x) ((x)->esp)
|
||||
#define PT_REGS_FP(x) ((x)->ebp)
|
||||
#define PT_REGS_RC(x) ((x)->eax)
|
||||
#define PT_REGS_SP(x) ((x)->esp)
|
||||
#define PT_REGS_IP(x) ((x)->eip)
|
||||
|
||||
#else /* __i386__ */
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), eax)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), edx)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), ecx)
|
||||
#define PT_REGS_PARM4_CORE(x) 0
|
||||
#define PT_REGS_PARM5_CORE(x) 0
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), esp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), ebp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), eax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), esp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), eip)
|
||||
|
||||
#define __PT_PARM1_REG rdi
|
||||
#define __PT_PARM2_REG rsi
|
||||
#define __PT_PARM3_REG rdx
|
||||
#define __PT_PARM4_REG rcx
|
||||
#define __PT_PARM5_REG r8
|
||||
#define __PT_RET_REG rsp
|
||||
#define __PT_FP_REG rbp
|
||||
#define __PT_RC_REG rax
|
||||
#define __PT_SP_REG rsp
|
||||
#define __PT_IP_REG rip
|
||||
/* syscall uses r10 for PARM4 */
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ((x)->r10)
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(x, r10)
|
||||
#else
|
||||
|
||||
#endif /* __i386__ */
|
||||
#define PT_REGS_PARM1(x) ((x)->rdi)
|
||||
#define PT_REGS_PARM2(x) ((x)->rsi)
|
||||
#define PT_REGS_PARM3(x) ((x)->rdx)
|
||||
#define PT_REGS_PARM4(x) ((x)->rcx)
|
||||
#define PT_REGS_PARM5(x) ((x)->r8)
|
||||
#define PT_REGS_RET(x) ((x)->rsp)
|
||||
#define PT_REGS_FP(x) ((x)->rbp)
|
||||
#define PT_REGS_RC(x) ((x)->rax)
|
||||
#define PT_REGS_SP(x) ((x)->rsp)
|
||||
#define PT_REGS_IP(x) ((x)->rip)
|
||||
|
||||
#endif /* __KERNEL__ || __VMLINUX_H__ */
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), rdi)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), rsi)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), rdx)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), rcx)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), rsp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), rbp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), rax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), rsp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), rip)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(bpf_target_s390)
|
||||
|
||||
struct pt_regs___s390 {
|
||||
unsigned long orig_gpr2;
|
||||
};
|
||||
|
||||
/* s390 provides user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const user_pt_regs *)(x))
|
||||
#define __PT_PARM1_REG gprs[2]
|
||||
#define __PT_PARM2_REG gprs[3]
|
||||
#define __PT_PARM3_REG gprs[4]
|
||||
#define __PT_PARM4_REG gprs[5]
|
||||
#define __PT_PARM5_REG gprs[6]
|
||||
#define __PT_RET_REG grps[14]
|
||||
#define __PT_FP_REG gprs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG gprs[2]
|
||||
#define __PT_SP_REG gprs[15]
|
||||
#define __PT_IP_REG psw.addr
|
||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___s390 *)(x), orig_gpr2)
|
||||
struct pt_regs;
|
||||
#define PT_REGS_S390 const volatile user_pt_regs
|
||||
#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2])
|
||||
#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3])
|
||||
#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4])
|
||||
#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5])
|
||||
#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6])
|
||||
#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14])
|
||||
/* Works only with CONFIG_FRAME_POINTER */
|
||||
#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11])
|
||||
#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2])
|
||||
#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15])
|
||||
#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[3])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[4])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[5])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[6])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[14])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[11])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[15])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), psw.addr)
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
#define __PT_PARM1_REG uregs[0]
|
||||
#define __PT_PARM2_REG uregs[1]
|
||||
#define __PT_PARM3_REG uregs[2]
|
||||
#define __PT_PARM4_REG uregs[3]
|
||||
#define __PT_PARM5_REG uregs[4]
|
||||
#define __PT_RET_REG uregs[14]
|
||||
#define __PT_FP_REG uregs[11] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG uregs[0]
|
||||
#define __PT_SP_REG uregs[13]
|
||||
#define __PT_IP_REG uregs[12]
|
||||
#define PT_REGS_PARM1(x) ((x)->uregs[0])
|
||||
#define PT_REGS_PARM2(x) ((x)->uregs[1])
|
||||
#define PT_REGS_PARM3(x) ((x)->uregs[2])
|
||||
#define PT_REGS_PARM4(x) ((x)->uregs[3])
|
||||
#define PT_REGS_PARM5(x) ((x)->uregs[4])
|
||||
#define PT_REGS_RET(x) ((x)->uregs[14])
|
||||
#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define PT_REGS_RC(x) ((x)->uregs[0])
|
||||
#define PT_REGS_SP(x) ((x)->uregs[13])
|
||||
#define PT_REGS_IP(x) ((x)->uregs[12])
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), uregs[0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), uregs[1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), uregs[2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), uregs[3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), uregs[4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), uregs[14])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), uregs[11])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), uregs[0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), uregs[13])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), uregs[12])
|
||||
|
||||
#elif defined(bpf_target_arm64)
|
||||
|
||||
struct pt_regs___arm64 {
|
||||
unsigned long orig_x0;
|
||||
};
|
||||
|
||||
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))
|
||||
#define __PT_PARM1_REG regs[0]
|
||||
#define __PT_PARM2_REG regs[1]
|
||||
#define __PT_PARM3_REG regs[2]
|
||||
#define __PT_PARM4_REG regs[3]
|
||||
#define __PT_PARM5_REG regs[4]
|
||||
#define __PT_RET_REG regs[30]
|
||||
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG regs[0]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG pc
|
||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma("GCC error \"use PT_REGS_PARM1_CORE_SYSCALL() instead\""); 0l; })
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ((const struct pt_regs___arm64 *)(x), orig_x0)
|
||||
struct pt_regs;
|
||||
#define PT_REGS_ARM64 const volatile struct user_pt_regs
|
||||
#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])
|
||||
#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])
|
||||
#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2])
|
||||
#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3])
|
||||
#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4])
|
||||
#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30])
|
||||
/* Works only with CONFIG_FRAME_POINTER */
|
||||
#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29])
|
||||
#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0])
|
||||
#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)
|
||||
#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[30])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[29])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), pc)
|
||||
|
||||
#elif defined(bpf_target_mips)
|
||||
|
||||
#define __PT_PARM1_REG regs[4]
|
||||
#define __PT_PARM2_REG regs[5]
|
||||
#define __PT_PARM3_REG regs[6]
|
||||
#define __PT_PARM4_REG regs[7]
|
||||
#define __PT_PARM5_REG regs[8]
|
||||
#define __PT_RET_REG regs[31]
|
||||
#define __PT_FP_REG regs[30] /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define __PT_RC_REG regs[2]
|
||||
#define __PT_SP_REG regs[29]
|
||||
#define __PT_IP_REG cp0_epc
|
||||
#define PT_REGS_PARM1(x) ((x)->regs[4])
|
||||
#define PT_REGS_PARM2(x) ((x)->regs[5])
|
||||
#define PT_REGS_PARM3(x) ((x)->regs[6])
|
||||
#define PT_REGS_PARM4(x) ((x)->regs[7])
|
||||
#define PT_REGS_PARM5(x) ((x)->regs[8])
|
||||
#define PT_REGS_RET(x) ((x)->regs[31])
|
||||
#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */
|
||||
#define PT_REGS_RC(x) ((x)->regs[1])
|
||||
#define PT_REGS_SP(x) ((x)->regs[29])
|
||||
#define PT_REGS_IP(x) ((x)->cp0_epc)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), regs[4])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), regs[5])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), regs[6])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), regs[7])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), regs[8])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), regs[31])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), regs[30])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), regs[1])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), regs[29])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), cp0_epc)
|
||||
|
||||
#elif defined(bpf_target_powerpc)
|
||||
|
||||
#define __PT_PARM1_REG gpr[3]
|
||||
#define __PT_PARM2_REG gpr[4]
|
||||
#define __PT_PARM3_REG gpr[5]
|
||||
#define __PT_PARM4_REG gpr[6]
|
||||
#define __PT_PARM5_REG gpr[7]
|
||||
#define __PT_RET_REG regs[31]
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG gpr[3]
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG nip
|
||||
/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
#define PT_REGS_PARM1(x) ((x)->gpr[3])
|
||||
#define PT_REGS_PARM2(x) ((x)->gpr[4])
|
||||
#define PT_REGS_PARM3(x) ((x)->gpr[5])
|
||||
#define PT_REGS_PARM4(x) ((x)->gpr[6])
|
||||
#define PT_REGS_PARM5(x) ((x)->gpr[7])
|
||||
#define PT_REGS_RC(x) ((x)->gpr[3])
|
||||
#define PT_REGS_SP(x) ((x)->sp)
|
||||
#define PT_REGS_IP(x) ((x)->nip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), gpr[3])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), gpr[4])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), gpr[5])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), gpr[6])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), gpr[7])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), gpr[3])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), nip)
|
||||
|
||||
#elif defined(bpf_target_sparc)
|
||||
|
||||
#define __PT_PARM1_REG u_regs[UREG_I0]
|
||||
#define __PT_PARM2_REG u_regs[UREG_I1]
|
||||
#define __PT_PARM3_REG u_regs[UREG_I2]
|
||||
#define __PT_PARM4_REG u_regs[UREG_I3]
|
||||
#define __PT_PARM5_REG u_regs[UREG_I4]
|
||||
#define __PT_RET_REG u_regs[UREG_I7]
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG u_regs[UREG_I0]
|
||||
#define __PT_SP_REG u_regs[UREG_FP]
|
||||
#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])
|
||||
#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1])
|
||||
#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2])
|
||||
#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3])
|
||||
#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4])
|
||||
#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7])
|
||||
#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])
|
||||
#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I7])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), u_regs[UREG_FP])
|
||||
|
||||
/* Should this also be a bpf_target check for the sparc case? */
|
||||
#if defined(__arch64__)
|
||||
#define __PT_IP_REG tpc
|
||||
#define PT_REGS_IP(x) ((x)->tpc)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), tpc)
|
||||
#else
|
||||
#define __PT_IP_REG pc
|
||||
#define PT_REGS_IP(x) ((x)->pc)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc)
|
||||
#endif
|
||||
|
||||
#elif defined(bpf_target_riscv)
|
||||
|
||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||
#define __PT_PARM1_REG a0
|
||||
#define __PT_PARM2_REG a1
|
||||
#define __PT_PARM3_REG a2
|
||||
#define __PT_PARM4_REG a3
|
||||
#define __PT_PARM5_REG a4
|
||||
#define __PT_RET_REG ra
|
||||
#define __PT_FP_REG s0
|
||||
#define __PT_RC_REG a5
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG pc
|
||||
/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#elif defined(bpf_target_arc)
|
||||
|
||||
/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))
|
||||
#define __PT_PARM1_REG scratch.r0
|
||||
#define __PT_PARM2_REG scratch.r1
|
||||
#define __PT_PARM3_REG scratch.r2
|
||||
#define __PT_PARM4_REG scratch.r3
|
||||
#define __PT_PARM5_REG scratch.r4
|
||||
#define __PT_RET_REG scratch.blink
|
||||
#define __PT_FP_REG __unsupported__
|
||||
#define __PT_RC_REG scratch.r0
|
||||
#define __PT_SP_REG scratch.sp
|
||||
#define __PT_IP_REG scratch.ret
|
||||
/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ctx
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(bpf_target_defined)
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
/* allow some architecutres to override `struct pt_regs` */
|
||||
#ifndef __PT_REGS_CAST
|
||||
#define __PT_REGS_CAST(x) (x)
|
||||
#endif
|
||||
|
||||
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
|
||||
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
|
||||
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
|
||||
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
|
||||
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
|
||||
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
|
||||
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
|
||||
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
|
||||
#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)
|
||||
#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_REG)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_REG)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_SP_REG)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_IP_REG)
|
||||
|
||||
#if defined(bpf_target_powerpc)
|
||||
|
||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; })
|
||||
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||||
|
||||
#elif defined(bpf_target_sparc)
|
||||
|
||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); })
|
||||
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||||
|
||||
#else
|
||||
|
||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) \
|
||||
({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
||||
({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
||||
#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \
|
||||
({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||||
|
||||
({ bpf_probe_read(&(ip), sizeof(ip), \
|
||||
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||||
#endif
|
||||
|
||||
#ifndef PT_REGS_PARM1_SYSCALL
|
||||
#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM2_SYSCALL(x) PT_REGS_PARM2(x)
|
||||
#define PT_REGS_PARM3_SYSCALL(x) PT_REGS_PARM3(x)
|
||||
#ifndef PT_REGS_PARM4_SYSCALL
|
||||
#define PT_REGS_PARM4_SYSCALL(x) PT_REGS_PARM4(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM5_SYSCALL(x) PT_REGS_PARM5(x)
|
||||
|
||||
#ifndef PT_REGS_PARM1_CORE_SYSCALL
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) PT_REGS_PARM1_CORE(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) PT_REGS_PARM2_CORE(x)
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) PT_REGS_PARM3_CORE(x)
|
||||
#ifndef PT_REGS_PARM4_CORE_SYSCALL
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) PT_REGS_PARM4_CORE(x)
|
||||
#endif
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) PT_REGS_PARM5_CORE(x)
|
||||
|
||||
#else /* defined(bpf_target_defined) */
|
||||
|
||||
#define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM2_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
#define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })
|
||||
|
||||
#endif /* defined(bpf_target_defined) */
|
||||
|
||||
/*
|
||||
* When invoked from a syscall handler kprobe, returns a pointer to a
|
||||
* struct pt_regs containing syscall arguments and suitable for passing to
|
||||
* PT_REGS_PARMn_SYSCALL() and PT_REGS_PARMn_CORE_SYSCALL().
|
||||
*/
|
||||
#ifndef PT_REGS_SYSCALL_REGS
|
||||
/* By default, assume that the arch selects ARCH_HAS_SYSCALL_WRAPPER. */
|
||||
#define PT_REGS_SYSCALL_REGS(ctx) ((struct pt_regs *)PT_REGS_PARM1(ctx))
|
||||
#endif
|
||||
|
||||
#ifndef ___bpf_concat
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#endif
|
||||
#ifndef ___bpf_apply
|
||||
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
|
||||
#endif
|
||||
#ifndef ___bpf_nth
|
||||
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
|
||||
#endif
|
||||
#ifndef ___bpf_narg
|
||||
#define ___bpf_narg(...) ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#endif
|
||||
#define ___bpf_narg(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define ___bpf_empty(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)
|
||||
|
||||
#define ___bpf_ctx_cast0() ctx
|
||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
||||
#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1]
|
||||
#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2]
|
||||
#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3]
|
||||
#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4]
|
||||
#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5]
|
||||
#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6]
|
||||
#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7]
|
||||
#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8]
|
||||
#define ___bpf_ctx_cast0() ctx
|
||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
||||
#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1]
|
||||
#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2]
|
||||
#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3]
|
||||
#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4]
|
||||
#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5]
|
||||
#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6]
|
||||
#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7]
|
||||
#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8]
|
||||
#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9]
|
||||
#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10]
|
||||
#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11]
|
||||
#define ___bpf_ctx_cast(args...) ___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)
|
||||
#define ___bpf_ctx_cast(args...) \
|
||||
___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and
|
||||
@@ -438,13 +350,19 @@ ____##name(unsigned long long *ctx, ##args)
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
#define ___bpf_kprobe_args0() ctx
|
||||
#define ___bpf_kprobe_args1(x) ___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)
|
||||
#define ___bpf_kprobe_args2(x, args...) ___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)
|
||||
#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
||||
#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
||||
#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
||||
#define ___bpf_kprobe_args(args...) ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
||||
#define ___bpf_kprobe_args0() ctx
|
||||
#define ___bpf_kprobe_args1(x) \
|
||||
___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)
|
||||
#define ___bpf_kprobe_args2(x, args...) \
|
||||
___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)
|
||||
#define ___bpf_kprobe_args3(x, args...) \
|
||||
___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
||||
#define ___bpf_kprobe_args4(x, args...) \
|
||||
___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
||||
#define ___bpf_kprobe_args5(x, args...) \
|
||||
___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
||||
#define ___bpf_kprobe_args(args...) \
|
||||
___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for
|
||||
@@ -470,9 +388,11 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#define ___bpf_kretprobe_args0() ctx
|
||||
#define ___bpf_kretprobe_args1(x) ___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)
|
||||
#define ___bpf_kretprobe_args(args...) ___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)
|
||||
#define ___bpf_kretprobe_args0() ctx
|
||||
#define ___bpf_kretprobe_args1(x) \
|
||||
___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)
|
||||
#define ___bpf_kretprobe_args(args...) \
|
||||
___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional
|
||||
@@ -493,39 +413,20 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
} \
|
||||
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#define ___bpf_syscall_args0() ctx
|
||||
#define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs)
|
||||
#define ___bpf_syscall_args(args...) ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_KPROBE_SYSCALL is a variant of BPF_KPROBE, which is intended for
|
||||
* tracing syscall functions, like __x64_sys_close. It hides the underlying
|
||||
* platform-specific low-level way of getting syscall input arguments from
|
||||
* struct pt_regs, and provides a familiar typed and named function arguments
|
||||
* syntax and semantics of accessing syscall input parameters.
|
||||
*
|
||||
* Original struct pt_regs* context is preserved as 'ctx' argument. This might
|
||||
* be necessary when using BPF helpers like bpf_perf_event_output().
|
||||
*
|
||||
* This macro relies on BPF CO-RE support.
|
||||
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
|
||||
* in a structure.
|
||||
*/
|
||||
#define BPF_KPROBE_SYSCALL(name, args...) \
|
||||
name(struct pt_regs *ctx); \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args); \
|
||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
{ \
|
||||
struct pt_regs *regs = PT_REGS_SYSCALL_REGS(ctx); \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
return ____##name(___bpf_syscall_args(args)); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
} \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args)
|
||||
#define BPF_SEQ_PRINTF(seq, fmt, args...) \
|
||||
({ \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
static const char ___fmt[] = fmt; \
|
||||
unsigned long long ___param[] = { args }; \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
int ___ret = bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
|
||||
___param, sizeof(___param)); \
|
||||
___ret; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
403
src/btf.h
403
src/btf.h
@@ -1,12 +1,10 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
/*! \file */
|
||||
|
||||
#ifndef __LIBBPF_BTF_H
|
||||
#define __LIBBPF_BTF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
@@ -26,306 +24,106 @@ struct btf_type;
|
||||
|
||||
struct bpf_object;
|
||||
|
||||
enum btf_endianness {
|
||||
BTF_LITTLE_ENDIAN = 0,
|
||||
BTF_BIG_ENDIAN = 1,
|
||||
/*
|
||||
* The .BTF.ext ELF section layout defined as
|
||||
* struct btf_ext_header
|
||||
* func_info subsection
|
||||
*
|
||||
* The func_info subsection layout:
|
||||
* record size for struct bpf_func_info in the func_info subsection
|
||||
* 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_sec_func_info for section #2
|
||||
* a list of bpf_func_info records for section #2
|
||||
* ......
|
||||
*
|
||||
* Note that the bpf_func_info record size in .BTF.ext may not
|
||||
* be the same as the one defined in include/uapi/linux/bpf.h.
|
||||
* The loader should ensure that record_size meets minimum
|
||||
* requirement and pass the record as is to the kernel. The
|
||||
* kernel will handle the func_info properly based on its contents.
|
||||
*/
|
||||
struct btf_ext_header {
|
||||
__u16 magic;
|
||||
__u8 version;
|
||||
__u8 flags;
|
||||
__u32 hdr_len;
|
||||
|
||||
/* All offsets are in bytes relative to the end of this header */
|
||||
__u32 func_info_off;
|
||||
__u32 func_info_len;
|
||||
__u32 line_info_off;
|
||||
__u32 line_info_len;
|
||||
|
||||
/* optional part of .BTF.ext header */
|
||||
__u32 field_reloc_off;
|
||||
__u32 field_reloc_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief **btf__free()** frees all data of a BTF object
|
||||
* @param btf BTF object to free
|
||||
*/
|
||||
LIBBPF_API void btf__free(struct btf *btf);
|
||||
|
||||
/**
|
||||
* @brief **btf__new()** creates a new instance of a BTF object from the raw
|
||||
* bytes of an ELF's BTF section
|
||||
* @param data raw bytes
|
||||
* @param size number of bytes passed in `data`
|
||||
* @return new BTF object instance which has to be eventually freed with
|
||||
* **btf__free()**
|
||||
*
|
||||
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
|
||||
* error code from such a pointer `libbpf_get_error()` should be used. If
|
||||
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
|
||||
* returned on error instead. In both cases thread-local `errno` variable is
|
||||
* always set to error code as well.
|
||||
*/
|
||||
LIBBPF_API struct btf *btf__new(const void *data, __u32 size);
|
||||
|
||||
/**
|
||||
* @brief **btf__new_split()** create a new instance of a BTF object from the
|
||||
* provided raw data bytes. It takes another BTF instance, **base_btf**, which
|
||||
* serves as a base BTF, which is extended by types in a newly created BTF
|
||||
* instance
|
||||
* @param data raw bytes
|
||||
* @param size length of raw bytes
|
||||
* @param base_btf the base BTF object
|
||||
* @return new BTF object instance which has to be eventually freed with
|
||||
* **btf__free()**
|
||||
*
|
||||
* If *base_btf* is NULL, `btf__new_split()` is equivalent to `btf__new()` and
|
||||
* creates non-split BTF.
|
||||
*
|
||||
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
|
||||
* error code from such a pointer `libbpf_get_error()` should be used. If
|
||||
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
|
||||
* returned on error instead. In both cases thread-local `errno` variable is
|
||||
* always set to error code as well.
|
||||
*/
|
||||
LIBBPF_API struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf);
|
||||
|
||||
/**
|
||||
* @brief **btf__new_empty()** creates an empty BTF object. Use
|
||||
* `btf__add_*()` to populate such BTF object.
|
||||
* @return new BTF object instance which has to be eventually freed with
|
||||
* **btf__free()**
|
||||
*
|
||||
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
|
||||
* error code from such a pointer `libbpf_get_error()` should be used. If
|
||||
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
|
||||
* returned on error instead. In both cases thread-local `errno` variable is
|
||||
* always set to error code as well.
|
||||
*/
|
||||
LIBBPF_API struct btf *btf__new_empty(void);
|
||||
|
||||
/**
|
||||
* @brief **btf__new_empty_split()** creates an unpopulated BTF object from an
|
||||
* ELF BTF section except with a base BTF on top of which split BTF should be
|
||||
* based
|
||||
* @return new BTF object instance which has to be eventually freed with
|
||||
* **btf__free()**
|
||||
*
|
||||
* If *base_btf* is NULL, `btf__new_empty_split()` is equivalent to
|
||||
* `btf__new_empty()` and creates non-split BTF.
|
||||
*
|
||||
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
|
||||
* error code from such a pointer `libbpf_get_error()` should be used. If
|
||||
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
|
||||
* returned on error instead. In both cases thread-local `errno` variable is
|
||||
* always set to error code as well.
|
||||
*/
|
||||
LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_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);
|
||||
LIBBPF_API struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf);
|
||||
LIBBPF_API struct btf *btf__parse_raw(const char *path);
|
||||
LIBBPF_API struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf);
|
||||
|
||||
LIBBPF_API struct btf *btf__load_vmlinux_btf(void);
|
||||
LIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf);
|
||||
LIBBPF_API struct btf *libbpf_find_kernel_btf(void);
|
||||
|
||||
LIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id);
|
||||
LIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_from_kernel_by_id instead")
|
||||
LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "intended for internal libbpf use only")
|
||||
LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size);
|
||||
LIBBPF_API struct btf *btf__parse_elf(const char *path,
|
||||
struct btf_ext **btf_ext);
|
||||
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_into_kernel instead")
|
||||
LIBBPF_API int btf__load(struct btf *btf);
|
||||
LIBBPF_API int btf__load_into_kernel(struct btf *btf);
|
||||
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
||||
const char *type_name);
|
||||
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
|
||||
const char *type_name, __u32 kind);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use btf__type_cnt() instead; note that btf__get_nr_types() == btf__type_cnt() - 1")
|
||||
LIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);
|
||||
LIBBPF_API __u32 btf__type_cnt(const struct btf *btf);
|
||||
LIBBPF_API const struct btf *btf__base_btf(const struct btf *btf);
|
||||
LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,
|
||||
__u32 id);
|
||||
LIBBPF_API size_t btf__pointer_size(const struct btf *btf);
|
||||
LIBBPF_API int btf__set_pointer_size(struct btf *btf, size_t ptr_sz);
|
||||
LIBBPF_API enum btf_endianness btf__endianness(const struct btf *btf);
|
||||
LIBBPF_API int btf__set_endianness(struct btf *btf, enum btf_endianness endian);
|
||||
LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
||||
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||
LIBBPF_API int btf__align_of(const struct btf *btf, __u32 id);
|
||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||
LIBBPF_API void btf__set_fd(struct btf *btf, int fd);
|
||||
LIBBPF_API const void *btf__raw_data(const struct btf *btf, __u32 *size);
|
||||
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "this API is not necessary when BTF-defined maps are used")
|
||||
LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||
LIBBPF_API int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
||||
__u32 expected_key_size,
|
||||
__u32 expected_value_size,
|
||||
__u32 *key_type_id, __u32 *value_type_id);
|
||||
|
||||
LIBBPF_API struct btf_ext *btf_ext__new(const __u8 *data, __u32 size);
|
||||
LIBBPF_API struct btf_ext *btf_ext__new(__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 LIBBPF_DEPRECATED("btf_ext__reloc_func_info was never meant as a public API and has wrong assumptions embedded in it; it will be removed in the future libbpf versions")
|
||||
int btf_ext__reloc_func_info(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt,
|
||||
void **func_info, __u32 *cnt);
|
||||
LIBBPF_API LIBBPF_DEPRECATED("btf_ext__reloc_line_info was never meant as a public API and has wrong assumptions embedded in it; it will be removed in the future libbpf versions")
|
||||
int btf_ext__reloc_line_info(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt,
|
||||
void **line_info, __u32 *cnt);
|
||||
LIBBPF_API LIBBPF_DEPRECATED("btf_ext__reloc_func_info is deprecated; write custom func_info parsing to fetch rec_size")
|
||||
__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
||||
LIBBPF_API LIBBPF_DEPRECATED("btf_ext__reloc_line_info is deprecated; write custom line_info parsing to fetch rec_size")
|
||||
__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
||||
LIBBPF_API const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext,
|
||||
__u32 *size);
|
||||
LIBBPF_API int btf_ext__reloc_func_info(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt,
|
||||
void **func_info, __u32 *cnt);
|
||||
LIBBPF_API int btf_ext__reloc_line_info(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt,
|
||||
void **line_info, __u32 *cnt);
|
||||
LIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
||||
LIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
||||
|
||||
LIBBPF_API int btf__find_str(struct btf *btf, const char *s);
|
||||
LIBBPF_API int btf__add_str(struct btf *btf, const char *s);
|
||||
LIBBPF_API int btf__add_type(struct btf *btf, const struct btf *src_btf,
|
||||
const struct btf_type *src_type);
|
||||
/**
|
||||
* @brief **btf__add_btf()** appends all the BTF types from *src_btf* into *btf*
|
||||
* @param btf BTF object which all the BTF types and strings are added to
|
||||
* @param src_btf BTF object which all BTF types and referenced strings are copied from
|
||||
* @return BTF type ID of the first appended BTF type, or negative error code
|
||||
*
|
||||
* **btf__add_btf()** can be used to simply and efficiently append the entire
|
||||
* contents of one BTF object to another one. All the BTF type data is copied
|
||||
* over, all referenced type IDs are adjusted by adding a necessary ID offset.
|
||||
* Only strings referenced from BTF types are copied over and deduplicated, so
|
||||
* if there were some unused strings in *src_btf*, those won't be copied over,
|
||||
* which is consistent with the general string deduplication semantics of BTF
|
||||
* writing APIs.
|
||||
*
|
||||
* If any error is encountered during this process, the contents of *btf* is
|
||||
* left intact, which means that **btf__add_btf()** follows the transactional
|
||||
* semantics and the operation as a whole is all-or-nothing.
|
||||
*
|
||||
* *src_btf* has to be non-split BTF, as of now copying types from split BTF
|
||||
* is not supported and will result in -ENOTSUP error code returned.
|
||||
*/
|
||||
LIBBPF_API int btf__add_btf(struct btf *btf, const struct btf *src_btf);
|
||||
|
||||
LIBBPF_API int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding);
|
||||
LIBBPF_API int btf__add_float(struct btf *btf, const char *name, size_t byte_sz);
|
||||
LIBBPF_API int btf__add_ptr(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_array(struct btf *btf,
|
||||
int index_type_id, int elem_type_id, __u32 nr_elems);
|
||||
/* struct/union construction APIs */
|
||||
LIBBPF_API int btf__add_struct(struct btf *btf, const char *name, __u32 sz);
|
||||
LIBBPF_API int btf__add_union(struct btf *btf, const char *name, __u32 sz);
|
||||
LIBBPF_API int btf__add_field(struct btf *btf, const char *name, int field_type_id,
|
||||
__u32 bit_offset, __u32 bit_size);
|
||||
|
||||
/* enum construction APIs */
|
||||
LIBBPF_API int btf__add_enum(struct btf *btf, const char *name, __u32 bytes_sz);
|
||||
LIBBPF_API int btf__add_enum_value(struct btf *btf, const char *name, __s64 value);
|
||||
|
||||
enum btf_fwd_kind {
|
||||
BTF_FWD_STRUCT = 0,
|
||||
BTF_FWD_UNION = 1,
|
||||
BTF_FWD_ENUM = 2,
|
||||
};
|
||||
|
||||
LIBBPF_API int btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind);
|
||||
LIBBPF_API int btf__add_typedef(struct btf *btf, const char *name, int ref_type_id);
|
||||
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);
|
||||
|
||||
/* func and func_proto construction APIs */
|
||||
LIBBPF_API int btf__add_func(struct btf *btf, const char *name,
|
||||
enum btf_func_linkage linkage, int proto_type_id);
|
||||
LIBBPF_API int btf__add_func_proto(struct btf *btf, int ret_type_id);
|
||||
LIBBPF_API int btf__add_func_param(struct btf *btf, const char *name, int type_id);
|
||||
|
||||
/* var & datasec construction APIs */
|
||||
LIBBPF_API int btf__add_var(struct btf *btf, const char *name, int linkage, int type_id);
|
||||
LIBBPF_API int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz);
|
||||
LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,
|
||||
__u32 offset, __u32 byte_sz);
|
||||
|
||||
/* 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 struct btf *libbpf_find_kernel_btf(void);
|
||||
|
||||
struct btf_dedup_opts {
|
||||
size_t sz;
|
||||
/* optional .BTF.ext info to dedup along the main BTF info */
|
||||
struct btf_ext *btf_ext;
|
||||
/* force hash collisions (used for testing) */
|
||||
bool force_collisions;
|
||||
size_t :0;
|
||||
unsigned int dedup_table_size;
|
||||
bool dont_resolve_fwds;
|
||||
};
|
||||
#define btf_dedup_opts__last_field force_collisions
|
||||
|
||||
LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
|
||||
LIBBPF_API int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use btf__dedup() instead")
|
||||
LIBBPF_API int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *opts);
|
||||
#define btf__dedup(...) ___libbpf_overload(___btf_dedup, __VA_ARGS__)
|
||||
#define ___btf_dedup3(btf, btf_ext, opts) btf__dedup_deprecated(btf, btf_ext, opts)
|
||||
#define ___btf_dedup2(btf, opts) btf__dedup(btf, opts)
|
||||
LIBBPF_API int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const struct btf_dedup_opts *opts);
|
||||
|
||||
struct btf_dump;
|
||||
|
||||
struct btf_dump_opts {
|
||||
union {
|
||||
size_t sz;
|
||||
void *ctx; /* DEPRECATED: will be gone in v1.0 */
|
||||
};
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
typedef void (*btf_dump_printf_fn_t)(void *ctx, const char *fmt, va_list args);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new(const struct btf *btf,
|
||||
btf_dump_printf_fn_t printf_fn,
|
||||
void *ctx,
|
||||
const struct btf_dump_opts *opts);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new_v0_6_0(const struct btf *btf,
|
||||
btf_dump_printf_fn_t printf_fn,
|
||||
void *ctx,
|
||||
const struct btf_dump_opts *opts);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new_deprecated(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn);
|
||||
|
||||
/* Choose either btf_dump__new() or btf_dump__new_deprecated() based on the
|
||||
* type of 4th argument. If it's btf_dump's print callback, use deprecated
|
||||
* API; otherwise, choose the new btf_dump__new(). ___libbpf_override()
|
||||
* doesn't work here because both variants have 4 input arguments.
|
||||
*
|
||||
* (void *) casts are necessary to avoid compilation warnings about type
|
||||
* mismatches, because even though __builtin_choose_expr() only ever evaluates
|
||||
* one side the other side still has to satisfy type constraints (this is
|
||||
* compiler implementation limitation which might be lifted eventually,
|
||||
* according to the documentation). So passing struct btf_ext in place of
|
||||
* btf_dump_printf_fn_t would be generating compilation warning. Casting to
|
||||
* void * avoids this issue.
|
||||
*
|
||||
* Also, two type compatibility checks for a function and function pointer are
|
||||
* required because passing function reference into btf_dump__new() as
|
||||
* btf_dump__new(..., my_callback, ...) and as btf_dump__new(...,
|
||||
* &my_callback, ...) (not explicit ampersand in the latter case) actually
|
||||
* differs as far as __builtin_types_compatible_p() is concerned. Thus two
|
||||
* checks are combined to detect callback argument.
|
||||
*
|
||||
* The rest works just like in case of ___libbpf_override() usage with symbol
|
||||
* versioning.
|
||||
*
|
||||
* C++ compilers don't support __builtin_types_compatible_p(), so at least
|
||||
* don't screw up compilation for them and let C++ users pick btf_dump__new
|
||||
* vs btf_dump__new_deprecated explicitly.
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
#define btf_dump__new(a1, a2, a3, a4) __builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(a4), btf_dump_printf_fn_t) || \
|
||||
__builtin_types_compatible_p(typeof(a4), void(void *, const char *, va_list)), \
|
||||
btf_dump__new_deprecated((void *)a1, (void *)a2, (void *)a3, (void *)a4), \
|
||||
btf_dump__new((void *)a1, (void *)a2, (void *)a3, (void *)a4))
|
||||
#endif
|
||||
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn);
|
||||
LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
||||
|
||||
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
||||
@@ -345,58 +143,16 @@ struct btf_dump_emit_type_decl_opts {
|
||||
* necessary indentation already
|
||||
*/
|
||||
int indent_level;
|
||||
/* strip all the const/volatile/restrict mods */
|
||||
bool strip_mods;
|
||||
size_t :0;
|
||||
};
|
||||
#define btf_dump_emit_type_decl_opts__last_field strip_mods
|
||||
#define btf_dump_emit_type_decl_opts__last_field indent_level
|
||||
|
||||
LIBBPF_API int
|
||||
btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
const struct btf_dump_emit_type_decl_opts *opts);
|
||||
|
||||
|
||||
struct btf_dump_type_data_opts {
|
||||
/* size of this struct, for forward/backward compatibility */
|
||||
size_t sz;
|
||||
const char *indent_str;
|
||||
int indent_level;
|
||||
/* below match "show" flags for bpf_show_snprintf() */
|
||||
bool compact; /* no newlines/indentation */
|
||||
bool skip_names; /* skip member/type names */
|
||||
bool emit_zeroes; /* show 0-valued fields */
|
||||
size_t :0;
|
||||
};
|
||||
#define btf_dump_type_data_opts__last_field emit_zeroes
|
||||
|
||||
LIBBPF_API int
|
||||
btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
|
||||
const void *data, size_t data_sz,
|
||||
const struct btf_dump_type_data_opts *opts);
|
||||
|
||||
/*
|
||||
* A set of helpers for easier BTF types handling.
|
||||
*
|
||||
* The inline functions below rely on constants from the kernel headers which
|
||||
* may not be available for applications including this header file. To avoid
|
||||
* compilation errors, we define all the constants here that were added after
|
||||
* the initial introduction of the BTF_KIND* constants.
|
||||
* A set of helpers for easier BTF types handling
|
||||
*/
|
||||
#ifndef BTF_KIND_FUNC
|
||||
#define BTF_KIND_FUNC 12 /* Function */
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||
#endif
|
||||
#ifndef BTF_KIND_VAR
|
||||
#define BTF_KIND_VAR 14 /* Variable */
|
||||
#define BTF_KIND_DATASEC 15 /* Section */
|
||||
#endif
|
||||
#ifndef BTF_KIND_FLOAT
|
||||
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||
#endif
|
||||
/* The kernel header switched to enums, so these two were never #defined */
|
||||
#define BTF_KIND_DECL_TAG 17 /* Decl Tag */
|
||||
#define BTF_KIND_TYPE_TAG 18 /* Type Tag */
|
||||
|
||||
static inline __u16 btf_kind(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info);
|
||||
@@ -412,11 +168,6 @@ static inline bool btf_kflag(const struct btf_type *t)
|
||||
return BTF_INFO_KFLAG(t->info);
|
||||
}
|
||||
|
||||
static inline bool btf_is_void(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_UNKN;
|
||||
}
|
||||
|
||||
static inline bool btf_is_int(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_INT;
|
||||
@@ -485,8 +236,7 @@ static inline bool btf_is_mod(const struct btf_type *t)
|
||||
|
||||
return kind == BTF_KIND_VOLATILE ||
|
||||
kind == BTF_KIND_CONST ||
|
||||
kind == BTF_KIND_RESTRICT ||
|
||||
kind == BTF_KIND_TYPE_TAG;
|
||||
kind == BTF_KIND_RESTRICT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_func(const struct btf_type *t)
|
||||
@@ -509,21 +259,6 @@ static inline bool btf_is_datasec(const struct btf_type *t)
|
||||
return btf_kind(t) == BTF_KIND_DATASEC;
|
||||
}
|
||||
|
||||
static inline bool btf_is_float(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_FLOAT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_DECL_TAG;
|
||||
}
|
||||
|
||||
static inline bool btf_is_type_tag(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_TYPE_TAG;
|
||||
}
|
||||
|
||||
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
||||
@@ -592,12 +327,6 @@ btf_var_secinfos(const struct btf_type *t)
|
||||
return (struct btf_var_secinfo *)(t + 1);
|
||||
}
|
||||
|
||||
struct btf_decl_tag;
|
||||
static inline struct btf_decl_tag *btf_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_decl_tag *)(t + 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
1085
src/btf_dump.c
1085
src/btf_dump.c
File diff suppressed because it is too large
Load Diff
1121
src/gen_loader.c
1121
src/gen_loader.c
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,6 @@
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
/* prevent accidental re-addition of reallocarray() */
|
||||
#pragma GCC poison reallocarray
|
||||
|
||||
/* start with 4 buckets */
|
||||
#define HASHMAP_MIN_CAP_BITS 2
|
||||
|
||||
@@ -75,7 +72,7 @@ void hashmap__clear(struct hashmap *map)
|
||||
|
||||
void hashmap__free(struct hashmap *map)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(map))
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
hashmap__clear(map);
|
||||
@@ -238,3 +235,4 @@ bool hashmap__delete(struct hashmap *map, const void *key,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,33 +11,14 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#ifndef __WORDSIZE
|
||||
#define __WORDSIZE (__SIZEOF_LONG__ * 8)
|
||||
#endif
|
||||
|
||||
static inline size_t hash_bits(size_t h, int bits)
|
||||
{
|
||||
/* shuffle bits and return requested number of upper bits */
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
|
||||
#if (__SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__)
|
||||
/* LP64 case */
|
||||
return (h * 11400714819323198485llu) >> (__SIZEOF_LONG_LONG__ * 8 - bits);
|
||||
#elif (__SIZEOF_SIZE_T__ <= __SIZEOF_LONG__)
|
||||
return (h * 2654435769lu) >> (__SIZEOF_LONG__ * 8 - bits);
|
||||
#else
|
||||
# error "Unsupported size_t size"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* generic C-string hashing function */
|
||||
static inline size_t str_hash(const char *s)
|
||||
{
|
||||
size_t h = 0;
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + *s;
|
||||
s++;
|
||||
}
|
||||
return h;
|
||||
return (h * 11400714819323198485llu) >> (__WORDSIZE - bits);
|
||||
}
|
||||
|
||||
typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);
|
||||
@@ -177,17 +158,17 @@ bool hashmap__find(const struct hashmap *map, const void *key, void **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)] \
|
||||
: NULL; \
|
||||
for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\
|
||||
map->cap_bits); \
|
||||
map->buckets ? map->buckets[bkt] : NULL; }); \
|
||||
cur; \
|
||||
cur = cur->next) \
|
||||
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)] \
|
||||
: NULL; \
|
||||
for (cur = ({ size_t bkt = hash_bits(map->hash_fn((_key), map->ctx),\
|
||||
map->cap_bits); \
|
||||
cur = map->buckets ? map->buckets[bkt] : NULL; }); \
|
||||
cur && ({ tmp = cur->next; true; }); \
|
||||
cur = tmp) \
|
||||
if (map->equal_fn(cur->key, (_key), map->ctx))
|
||||
|
||||
11012
src/libbpf.c
11012
src/libbpf.c
File diff suppressed because it is too large
Load Diff
1193
src/libbpf.h
1193
src/libbpf.h
File diff suppressed because it is too large
Load Diff
189
src/libbpf.map
189
src/libbpf.map
@@ -247,7 +247,6 @@ LIBBPF_0.0.8 {
|
||||
bpf_link_create;
|
||||
bpf_link_update;
|
||||
bpf_map__set_initial_value;
|
||||
bpf_prog_attach_opts;
|
||||
bpf_program__attach_cgroup;
|
||||
bpf_program__attach_lsm;
|
||||
bpf_program__is_lsm;
|
||||
@@ -271,191 +270,3 @@ LIBBPF_0.0.9 {
|
||||
ring_buffer__new;
|
||||
ring_buffer__poll;
|
||||
} LIBBPF_0.0.8;
|
||||
|
||||
LIBBPF_0.1.0 {
|
||||
global:
|
||||
bpf_link__detach;
|
||||
bpf_link_detach;
|
||||
bpf_map__ifindex;
|
||||
bpf_map__key_size;
|
||||
bpf_map__map_flags;
|
||||
bpf_map__max_entries;
|
||||
bpf_map__numa_node;
|
||||
bpf_map__set_key_size;
|
||||
bpf_map__set_map_flags;
|
||||
bpf_map__set_max_entries;
|
||||
bpf_map__set_numa_node;
|
||||
bpf_map__set_type;
|
||||
bpf_map__set_value_size;
|
||||
bpf_map__type;
|
||||
bpf_map__value_size;
|
||||
bpf_program__attach_xdp;
|
||||
bpf_program__autoload;
|
||||
bpf_program__is_sk_lookup;
|
||||
bpf_program__set_autoload;
|
||||
bpf_program__set_sk_lookup;
|
||||
btf__parse;
|
||||
btf__parse_raw;
|
||||
btf__pointer_size;
|
||||
btf__set_fd;
|
||||
btf__set_pointer_size;
|
||||
} LIBBPF_0.0.9;
|
||||
|
||||
LIBBPF_0.2.0 {
|
||||
global:
|
||||
bpf_prog_bind_map;
|
||||
bpf_prog_test_run_opts;
|
||||
bpf_program__attach_freplace;
|
||||
bpf_program__section_name;
|
||||
btf__add_array;
|
||||
btf__add_const;
|
||||
btf__add_enum;
|
||||
btf__add_enum_value;
|
||||
btf__add_datasec;
|
||||
btf__add_datasec_var_info;
|
||||
btf__add_field;
|
||||
btf__add_func;
|
||||
btf__add_func_param;
|
||||
btf__add_func_proto;
|
||||
btf__add_fwd;
|
||||
btf__add_int;
|
||||
btf__add_ptr;
|
||||
btf__add_restrict;
|
||||
btf__add_str;
|
||||
btf__add_struct;
|
||||
btf__add_typedef;
|
||||
btf__add_union;
|
||||
btf__add_var;
|
||||
btf__add_volatile;
|
||||
btf__endianness;
|
||||
btf__find_str;
|
||||
btf__new_empty;
|
||||
btf__set_endianness;
|
||||
btf__str_by_offset;
|
||||
perf_buffer__buffer_cnt;
|
||||
perf_buffer__buffer_fd;
|
||||
perf_buffer__epoll_fd;
|
||||
perf_buffer__consume_buffer;
|
||||
xsk_socket__create_shared;
|
||||
} LIBBPF_0.1.0;
|
||||
|
||||
LIBBPF_0.3.0 {
|
||||
global:
|
||||
btf__base_btf;
|
||||
btf__parse_elf_split;
|
||||
btf__parse_raw_split;
|
||||
btf__parse_split;
|
||||
btf__new_empty_split;
|
||||
btf__new_split;
|
||||
ring_buffer__epoll_fd;
|
||||
xsk_setup_xdp_prog;
|
||||
xsk_socket__update_xskmap;
|
||||
} LIBBPF_0.2.0;
|
||||
|
||||
LIBBPF_0.4.0 {
|
||||
global:
|
||||
btf__add_float;
|
||||
btf__add_type;
|
||||
bpf_linker__add_file;
|
||||
bpf_linker__finalize;
|
||||
bpf_linker__free;
|
||||
bpf_linker__new;
|
||||
bpf_map__inner_map;
|
||||
bpf_object__set_kversion;
|
||||
bpf_tc_attach;
|
||||
bpf_tc_detach;
|
||||
bpf_tc_hook_create;
|
||||
bpf_tc_hook_destroy;
|
||||
bpf_tc_query;
|
||||
} LIBBPF_0.3.0;
|
||||
|
||||
LIBBPF_0.5.0 {
|
||||
global:
|
||||
bpf_map__initial_value;
|
||||
bpf_map__pin_path;
|
||||
bpf_map_lookup_and_delete_elem_flags;
|
||||
bpf_program__attach_kprobe_opts;
|
||||
bpf_program__attach_perf_event_opts;
|
||||
bpf_program__attach_tracepoint_opts;
|
||||
bpf_program__attach_uprobe_opts;
|
||||
bpf_object__gen_loader;
|
||||
btf__load_from_kernel_by_id;
|
||||
btf__load_from_kernel_by_id_split;
|
||||
btf__load_into_kernel;
|
||||
btf__load_module_btf;
|
||||
btf__load_vmlinux_btf;
|
||||
btf_dump__dump_type_data;
|
||||
libbpf_set_strict_mode;
|
||||
} LIBBPF_0.4.0;
|
||||
|
||||
LIBBPF_0.6.0 {
|
||||
global:
|
||||
bpf_map__map_extra;
|
||||
bpf_map__set_map_extra;
|
||||
bpf_map_create;
|
||||
bpf_object__next_map;
|
||||
bpf_object__next_program;
|
||||
bpf_object__prev_map;
|
||||
bpf_object__prev_program;
|
||||
bpf_prog_load_deprecated;
|
||||
bpf_prog_load;
|
||||
bpf_program__flags;
|
||||
bpf_program__insn_cnt;
|
||||
bpf_program__insns;
|
||||
bpf_program__set_flags;
|
||||
btf__add_btf;
|
||||
btf__add_decl_tag;
|
||||
btf__add_type_tag;
|
||||
btf__dedup;
|
||||
btf__dedup_deprecated;
|
||||
btf__raw_data;
|
||||
btf__type_cnt;
|
||||
btf_dump__new;
|
||||
btf_dump__new_deprecated;
|
||||
libbpf_major_version;
|
||||
libbpf_minor_version;
|
||||
libbpf_version_string;
|
||||
perf_buffer__new;
|
||||
perf_buffer__new_deprecated;
|
||||
perf_buffer__new_raw;
|
||||
perf_buffer__new_raw_deprecated;
|
||||
} LIBBPF_0.5.0;
|
||||
|
||||
LIBBPF_0.7.0 {
|
||||
global:
|
||||
bpf_btf_load;
|
||||
bpf_program__expected_attach_type;
|
||||
bpf_program__log_buf;
|
||||
bpf_program__log_level;
|
||||
bpf_program__set_log_buf;
|
||||
bpf_program__set_log_level;
|
||||
bpf_program__type;
|
||||
bpf_xdp_attach;
|
||||
bpf_xdp_detach;
|
||||
bpf_xdp_query;
|
||||
bpf_xdp_query_id;
|
||||
libbpf_probe_bpf_helper;
|
||||
libbpf_probe_bpf_map_type;
|
||||
libbpf_probe_bpf_prog_type;
|
||||
libbpf_set_memlock_rlim_max;
|
||||
} LIBBPF_0.6.0;
|
||||
|
||||
LIBBPF_0.8.0 {
|
||||
global:
|
||||
bpf_map__autocreate;
|
||||
bpf_map__get_next_key;
|
||||
bpf_map__delete_elem;
|
||||
bpf_map__lookup_and_delete_elem;
|
||||
bpf_map__lookup_elem;
|
||||
bpf_map__set_autocreate;
|
||||
bpf_map__update_elem;
|
||||
bpf_map_delete_elem_flags;
|
||||
bpf_object__destroy_subskeleton;
|
||||
bpf_object__open_subskeleton;
|
||||
bpf_program__attach_kprobe_multi_opts;
|
||||
bpf_program__attach_trace_opts;
|
||||
bpf_program__attach_usdt;
|
||||
bpf_program__set_insns;
|
||||
libbpf_register_prog_handler;
|
||||
libbpf_unregister_prog_handler;
|
||||
} LIBBPF_0.7.0;
|
||||
|
||||
@@ -10,54 +10,11 @@
|
||||
#define __LIBBPF_LIBBPF_COMMON_H
|
||||
|
||||
#include <string.h>
|
||||
#include "libbpf_version.h"
|
||||
|
||||
#ifndef LIBBPF_API
|
||||
#define LIBBPF_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
|
||||
/* Mark a symbol as deprecated when libbpf version is >= {major}.{minor} */
|
||||
#define LIBBPF_DEPRECATED_SINCE(major, minor, msg) \
|
||||
__LIBBPF_MARK_DEPRECATED_ ## major ## _ ## minor \
|
||||
(LIBBPF_DEPRECATED("libbpf v" # major "." # minor "+: " msg))
|
||||
|
||||
#define __LIBBPF_CURRENT_VERSION_GEQ(major, minor) \
|
||||
(LIBBPF_MAJOR_VERSION > (major) || \
|
||||
(LIBBPF_MAJOR_VERSION == (major) && LIBBPF_MINOR_VERSION >= (minor)))
|
||||
|
||||
/* Add checks for other versions below when planning deprecation of API symbols
|
||||
* with the LIBBPF_DEPRECATED_SINCE macro.
|
||||
*/
|
||||
#if __LIBBPF_CURRENT_VERSION_GEQ(0, 6)
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_6(X) X
|
||||
#else
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_6(X)
|
||||
#endif
|
||||
#if __LIBBPF_CURRENT_VERSION_GEQ(0, 7)
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_7(X) X
|
||||
#else
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_7(X)
|
||||
#endif
|
||||
#if __LIBBPF_CURRENT_VERSION_GEQ(0, 8)
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_8(X) X
|
||||
#else
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_8(X)
|
||||
#endif
|
||||
|
||||
/* This set of internal macros allows to do "function overloading" based on
|
||||
* number of arguments provided by used in backwards-compatible way during the
|
||||
* transition to libbpf 1.0
|
||||
* It's ugly but necessary evil that will be cleaned up when we get to 1.0.
|
||||
* See bpf_prog_load() overload for example.
|
||||
*/
|
||||
#define ___libbpf_cat(A, B) A ## B
|
||||
#define ___libbpf_select(NAME, NUM) ___libbpf_cat(NAME, NUM)
|
||||
#define ___libbpf_nth(_1, _2, _3, _4, _5, _6, N, ...) N
|
||||
#define ___libbpf_cnt(...) ___libbpf_nth(__VA_ARGS__, 6, 5, 4, 3, 2, 1)
|
||||
#define ___libbpf_overload(NAME, ...) ___libbpf_select(NAME, ___libbpf_cnt(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
/* Helper macro to declare and initialize libbpf options struct
|
||||
*
|
||||
* This dance with uninitialized declaration, followed by memset to zero,
|
||||
@@ -71,7 +28,7 @@
|
||||
* including any extra padding, it with memset() and then assigns initial
|
||||
* values provided by users in struct initializer-syntax as varargs.
|
||||
*/
|
||||
#define LIBBPF_OPTS(TYPE, NAME, ...) \
|
||||
#define DECLARE_LIBBPF_OPTS(TYPE, NAME, ...) \
|
||||
struct TYPE NAME = ({ \
|
||||
memset(&NAME, 0, sizeof(struct TYPE)); \
|
||||
(struct TYPE) { \
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
@@ -40,7 +39,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
|
||||
int libbpf_strerror(int err, char *buf, size_t size)
|
||||
{
|
||||
if (!buf || !size)
|
||||
return libbpf_err(-EINVAL);
|
||||
return -1;
|
||||
|
||||
err = err > 0 ? err : -err;
|
||||
|
||||
@@ -49,7 +48,7 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
||||
|
||||
ret = strerror_r(err, buf, size);
|
||||
buf[size - 1] = '\0';
|
||||
return libbpf_err_errno(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (err < __LIBBPF_ERRNO__END) {
|
||||
@@ -63,5 +62,5 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
||||
|
||||
snprintf(buf, size, "Unknown libbpf error %d", err);
|
||||
buf[size - 1] = '\0';
|
||||
return libbpf_err(-ENOENT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -9,54 +9,7 @@
|
||||
#ifndef __LIBBPF_LIBBPF_INTERNAL_H
|
||||
#define __LIBBPF_LIBBPF_INTERNAL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "libbpf_legacy.h"
|
||||
#include "relo_core.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
/* prevent accidental re-addition of reallocarray() */
|
||||
#pragma GCC poison reallocarray
|
||||
|
||||
#include "libbpf.h"
|
||||
#include "btf.h"
|
||||
|
||||
#ifndef EM_BPF
|
||||
#define EM_BPF 247
|
||||
#endif
|
||||
|
||||
#ifndef R_BPF_64_64
|
||||
#define R_BPF_64_64 1
|
||||
#endif
|
||||
#ifndef R_BPF_64_ABS64
|
||||
#define R_BPF_64_ABS64 2
|
||||
#endif
|
||||
#ifndef R_BPF_64_ABS32
|
||||
#define R_BPF_64_ABS32 3
|
||||
#endif
|
||||
#ifndef R_BPF_64_32
|
||||
#define R_BPF_64_32 10
|
||||
#endif
|
||||
|
||||
#ifndef SHT_LLVM_ADDRSIG
|
||||
#define SHT_LLVM_ADDRSIG 0x6FFF4C03
|
||||
#endif
|
||||
|
||||
/* if libelf is old and doesn't support mmap(), fall back to read() */
|
||||
#ifndef ELF_C_READ_MMAP
|
||||
#define ELF_C_READ_MMAP ELF_C_READ
|
||||
#endif
|
||||
|
||||
/* Older libelf all end up in this expression, for both 32 and 64 bit */
|
||||
#ifndef ELF64_ST_VISIBILITY
|
||||
#define ELF64_ST_VISIBILITY(o) ((o) & 0x03)
|
||||
#endif
|
||||
|
||||
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
||||
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
||||
@@ -69,19 +22,7 @@
|
||||
#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
|
||||
#define BTF_PARAM_ENC(name, type) (name), (type)
|
||||
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
||||
#define BTF_TYPE_FLOAT_ENC(name, sz) \
|
||||
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)
|
||||
#define BTF_TYPE_DECL_TAG_ENC(value, type, component_idx) \
|
||||
BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx)
|
||||
#define BTF_TYPE_TYPE_TAG_ENC(value, type) \
|
||||
BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type)
|
||||
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#endif
|
||||
#ifndef min
|
||||
# define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
@@ -92,55 +33,21 @@
|
||||
# define offsetofend(TYPE, FIELD) \
|
||||
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
||||
#endif
|
||||
#ifndef __alias
|
||||
#define __alias(symbol) __attribute__((alias(#symbol)))
|
||||
#endif
|
||||
|
||||
/* Check whether a string `str` has prefix `pfx`, regardless if `pfx` is
|
||||
* a string literal known at compilation time or char * pointer known only at
|
||||
* runtime.
|
||||
*/
|
||||
#define str_has_pfx(str, pfx) \
|
||||
(strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
|
||||
|
||||
/* suffix check */
|
||||
static inline bool str_has_sfx(const char *str, const char *sfx)
|
||||
{
|
||||
size_t str_len = strlen(str);
|
||||
size_t sfx_len = strlen(sfx);
|
||||
|
||||
if (sfx_len <= str_len)
|
||||
return strcmp(str + str_len - sfx_len, sfx);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Symbol versioning is different between static and shared library.
|
||||
* Properly versioned symbols are needed for shared library, but
|
||||
* only the symbol of the new version is needed for static library.
|
||||
* Starting with GNU C 10, use symver attribute instead of .symver assembler
|
||||
* directive, which works better with GCC LTO builds.
|
||||
*/
|
||||
#if defined(SHARED) && defined(__GNUC__) && __GNUC__ >= 10
|
||||
|
||||
#define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
__attribute__((symver(#api_name "@@" #version)))
|
||||
#define COMPAT_VERSION(internal_name, api_name, version) \
|
||||
__attribute__((symver(#api_name "@" #version)))
|
||||
|
||||
#elif defined(SHARED)
|
||||
|
||||
#define COMPAT_VERSION(internal_name, api_name, version) \
|
||||
#ifdef SHARED
|
||||
# define COMPAT_VERSION(internal_name, api_name, version) \
|
||||
asm(".symver " #internal_name "," #api_name "@" #version);
|
||||
#define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
asm(".symver " #internal_name "," #api_name "@@" #version);
|
||||
|
||||
#else /* !SHARED */
|
||||
|
||||
#define COMPAT_VERSION(internal_name, api_name, version)
|
||||
#define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
#else
|
||||
# define COMPAT_VERSION(internal_name, api_name, version)
|
||||
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
extern typeof(internal_name) api_name \
|
||||
__attribute__((alias(#internal_name)));
|
||||
|
||||
#endif
|
||||
|
||||
extern void libbpf_print(enum libbpf_print_level level,
|
||||
@@ -156,129 +63,6 @@ do { \
|
||||
#define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__)
|
||||
#define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
struct bpf_link {
|
||||
int (*detach)(struct bpf_link *link);
|
||||
void (*dealloc)(struct bpf_link *link);
|
||||
char *pin_path; /* NULL, if not pinned */
|
||||
int fd; /* hook FD, -1 if not applicable */
|
||||
bool disconnected;
|
||||
};
|
||||
|
||||
/*
|
||||
* Re-implement glibc's reallocarray() for libbpf internal-only use.
|
||||
* reallocarray(), unfortunately, is not available in all versions of glibc,
|
||||
* so requires extra feature detection and using reallocarray() stub from
|
||||
* <tools/libc_compat.h> and COMPAT_NEED_REALLOCARRAY. All this complicates
|
||||
* build of libbpf unnecessarily and is just a maintenance burden. Instead,
|
||||
* it's trivial to implement libbpf-specific internal version and use it
|
||||
* throughout libbpf.
|
||||
*/
|
||||
static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total;
|
||||
|
||||
#if __has_builtin(__builtin_mul_overflow)
|
||||
if (unlikely(__builtin_mul_overflow(nmemb, size, &total)))
|
||||
return NULL;
|
||||
#else
|
||||
if (size == 0 || nmemb > ULONG_MAX / size)
|
||||
return NULL;
|
||||
total = nmemb * size;
|
||||
#endif
|
||||
return realloc(ptr, total);
|
||||
}
|
||||
|
||||
/* Copy up to sz - 1 bytes from zero-terminated src string and ensure that dst
|
||||
* is zero-terminated string no matter what (unless sz == 0, in which case
|
||||
* it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs
|
||||
* in what is returned. Given this is internal helper, it's trivial to extend
|
||||
* this, when necessary. Use this instead of strncpy inside libbpf source code.
|
||||
*/
|
||||
static inline void libbpf_strlcpy(char *dst, const char *src, size_t sz)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (sz == 0)
|
||||
return;
|
||||
|
||||
sz--;
|
||||
for (i = 0; i < sz && src[i]; i++)
|
||||
dst[i] = src[i];
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
__u32 get_kernel_version(void);
|
||||
|
||||
struct btf;
|
||||
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);
|
||||
|
||||
static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t)
|
||||
{
|
||||
return (enum btf_func_linkage)(int)btf_vlen(t);
|
||||
}
|
||||
|
||||
static inline __u32 btf_type_info(int kind, int vlen, int kflag)
|
||||
{
|
||||
return (kflag << 31) | (kind << 24) | vlen;
|
||||
}
|
||||
|
||||
enum map_def_parts {
|
||||
MAP_DEF_MAP_TYPE = 0x001,
|
||||
MAP_DEF_KEY_TYPE = 0x002,
|
||||
MAP_DEF_KEY_SIZE = 0x004,
|
||||
MAP_DEF_VALUE_TYPE = 0x008,
|
||||
MAP_DEF_VALUE_SIZE = 0x010,
|
||||
MAP_DEF_MAX_ENTRIES = 0x020,
|
||||
MAP_DEF_MAP_FLAGS = 0x040,
|
||||
MAP_DEF_NUMA_NODE = 0x080,
|
||||
MAP_DEF_PINNING = 0x100,
|
||||
MAP_DEF_INNER_MAP = 0x200,
|
||||
MAP_DEF_MAP_EXTRA = 0x400,
|
||||
|
||||
MAP_DEF_ALL = 0x7ff, /* combination of all above */
|
||||
};
|
||||
|
||||
struct btf_map_def {
|
||||
enum map_def_parts parts;
|
||||
__u32 map_type;
|
||||
__u32 key_type_id;
|
||||
__u32 key_size;
|
||||
__u32 value_type_id;
|
||||
__u32 value_size;
|
||||
__u32 max_entries;
|
||||
__u32 map_flags;
|
||||
__u32 numa_node;
|
||||
__u32 pinning;
|
||||
__u64 map_extra;
|
||||
};
|
||||
|
||||
int parse_btf_map_def(const char *map_name, struct btf *btf,
|
||||
const struct btf_type *def_t, bool strict,
|
||||
struct btf_map_def *map_def, struct btf_map_def *inner_def);
|
||||
|
||||
void *libbpf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
||||
size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
||||
int libbpf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
||||
|
||||
static inline bool libbpf_is_mem_zeroed(const char *p, ssize_t len)
|
||||
{
|
||||
while (len > 0) {
|
||||
if (*p)
|
||||
return false;
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool libbpf_validate_opts(const char *opts,
|
||||
size_t opts_sz, size_t user_sz,
|
||||
const char *type_name)
|
||||
@@ -287,9 +71,16 @@ static inline bool libbpf_validate_opts(const char *opts,
|
||||
pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
||||
return false;
|
||||
}
|
||||
if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {
|
||||
pr_warn("%s has non-zero extra bytes\n", type_name);
|
||||
return false;
|
||||
if (user_sz > opts_sz) {
|
||||
size_t i;
|
||||
|
||||
for (i = opts_sz; i < user_sz; i++) {
|
||||
if (opts[i]) {
|
||||
pr_warn("%s has non-zero extra bytes\n",
|
||||
type_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -303,70 +94,28 @@ static inline bool libbpf_validate_opts(const char *opts,
|
||||
((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
|
||||
#define OPTS_GET(opts, field, fallback_value) \
|
||||
(OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
|
||||
#define OPTS_SET(opts, field, value) \
|
||||
do { \
|
||||
if (OPTS_HAS(opts, field)) \
|
||||
(opts)->field = value; \
|
||||
} while (0)
|
||||
|
||||
#define OPTS_ZEROED(opts, last_nonzero_field) \
|
||||
({ \
|
||||
ssize_t __off = offsetofend(typeof(*(opts)), last_nonzero_field); \
|
||||
!(opts) || libbpf_is_mem_zeroed((const void *)opts + __off, \
|
||||
(opts)->sz - __off); \
|
||||
})
|
||||
|
||||
enum kern_feature_id {
|
||||
/* v4.14: kernel support for program & map names. */
|
||||
FEAT_PROG_NAME,
|
||||
/* v5.2: kernel support for global data sections. */
|
||||
FEAT_GLOBAL_DATA,
|
||||
/* BTF support */
|
||||
FEAT_BTF,
|
||||
/* BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support */
|
||||
FEAT_BTF_FUNC,
|
||||
/* BTF_KIND_VAR and BTF_KIND_DATASEC support */
|
||||
FEAT_BTF_DATASEC,
|
||||
/* BTF_FUNC_GLOBAL is supported */
|
||||
FEAT_BTF_GLOBAL_FUNC,
|
||||
/* BPF_F_MMAPABLE is supported for arrays */
|
||||
FEAT_ARRAY_MMAP,
|
||||
/* kernel support for expected_attach_type in BPF_PROG_LOAD */
|
||||
FEAT_EXP_ATTACH_TYPE,
|
||||
/* bpf_probe_read_{kernel,user}[_str] helpers */
|
||||
FEAT_PROBE_READ_KERN,
|
||||
/* BPF_PROG_BIND_MAP is supported */
|
||||
FEAT_PROG_BIND_MAP,
|
||||
/* Kernel support for module BTFs */
|
||||
FEAT_MODULE_BTF,
|
||||
/* BTF_KIND_FLOAT support */
|
||||
FEAT_BTF_FLOAT,
|
||||
/* BPF perf link support */
|
||||
FEAT_PERF_LINK,
|
||||
/* BTF_KIND_DECL_TAG support */
|
||||
FEAT_BTF_DECL_TAG,
|
||||
/* BTF_KIND_TYPE_TAG support */
|
||||
FEAT_BTF_TYPE_TAG,
|
||||
/* memcg-based accounting for BPF maps and progs */
|
||||
FEAT_MEMCG_ACCOUNT,
|
||||
/* BPF cookie (bpf_get_attach_cookie() BPF helper) support */
|
||||
FEAT_BPF_COOKIE,
|
||||
__FEAT_CNT,
|
||||
};
|
||||
|
||||
int probe_memcg_account(void);
|
||||
bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
|
||||
int bump_rlimit_memlock(void);
|
||||
|
||||
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
||||
int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len);
|
||||
int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level);
|
||||
|
||||
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
||||
void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
|
||||
const char **prefix, int *kind);
|
||||
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
||||
__u32 *size);
|
||||
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
||||
__u32 *off);
|
||||
|
||||
struct nlattr;
|
||||
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
|
||||
int libbpf_netlink_open(unsigned int *nl_pid);
|
||||
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
|
||||
int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex,
|
||||
libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie);
|
||||
int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
||||
libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
|
||||
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
||||
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
||||
|
||||
struct btf_ext_info {
|
||||
/*
|
||||
@@ -376,13 +125,6 @@ struct btf_ext_info {
|
||||
void *info;
|
||||
__u32 rec_size;
|
||||
__u32 len;
|
||||
/* optional (maintained internally by libbpf) mapping between .BTF.ext
|
||||
* section and corresponding ELF section. This is used to join
|
||||
* information like CO-RE relocation records with corresponding BPF
|
||||
* programs defined in ELF sections
|
||||
*/
|
||||
__u32 *sec_idxs;
|
||||
int sec_cnt;
|
||||
};
|
||||
|
||||
#define for_each_btf_ext_sec(seg, sec) \
|
||||
@@ -396,44 +138,6 @@ struct btf_ext_info {
|
||||
i < (sec)->num_info; \
|
||||
i++, rec = (void *)rec + (seg)->rec_size)
|
||||
|
||||
/*
|
||||
* The .BTF.ext ELF section layout defined as
|
||||
* struct btf_ext_header
|
||||
* func_info subsection
|
||||
*
|
||||
* The func_info subsection layout:
|
||||
* record size for struct bpf_func_info in the func_info subsection
|
||||
* 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_sec_func_info for section #2
|
||||
* a list of bpf_func_info records for section #2
|
||||
* ......
|
||||
*
|
||||
* Note that the bpf_func_info record size in .BTF.ext may not
|
||||
* be the same as the one defined in include/uapi/linux/bpf.h.
|
||||
* The loader should ensure that record_size meets minimum
|
||||
* requirement and pass the record as is to the kernel. The
|
||||
* kernel will handle the func_info properly based on its contents.
|
||||
*/
|
||||
struct btf_ext_header {
|
||||
__u16 magic;
|
||||
__u8 version;
|
||||
__u8 flags;
|
||||
__u32 hdr_len;
|
||||
|
||||
/* All offsets are in bytes relative to the end of this header */
|
||||
__u32 func_info_off;
|
||||
__u32 func_info_len;
|
||||
__u32 line_info_off;
|
||||
__u32 line_info_len;
|
||||
|
||||
/* optional part of .BTF.ext header */
|
||||
__u32 core_relo_off;
|
||||
__u32 core_relo_len;
|
||||
};
|
||||
|
||||
struct btf_ext {
|
||||
union {
|
||||
struct btf_ext_header *hdr;
|
||||
@@ -441,7 +145,7 @@ struct btf_ext {
|
||||
};
|
||||
struct btf_ext_info func_info;
|
||||
struct btf_ext_info line_info;
|
||||
struct btf_ext_info core_relo_info;
|
||||
struct btf_ext_info field_reloc_info;
|
||||
__u32 data_size;
|
||||
};
|
||||
|
||||
@@ -466,118 +170,67 @@ struct bpf_line_info_min {
|
||||
__u32 line_col;
|
||||
};
|
||||
|
||||
|
||||
typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);
|
||||
typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);
|
||||
int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx);
|
||||
int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx);
|
||||
int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
|
||||
int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
|
||||
__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
|
||||
__u32 kind);
|
||||
|
||||
extern enum libbpf_strict_mode libbpf_mode;
|
||||
|
||||
typedef int (*kallsyms_cb_t)(unsigned long long sym_addr, char sym_type,
|
||||
const char *sym_name, void *ctx);
|
||||
|
||||
int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *arg);
|
||||
|
||||
/* handle direct returned errors */
|
||||
static inline int libbpf_err(int ret)
|
||||
{
|
||||
if (ret < 0)
|
||||
errno = -ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* handle errno-based (e.g., syscall or libc) errors according to libbpf's
|
||||
* strict mode settings
|
||||
/* bpf_field_info_kind encodes which aspect of captured field has to be
|
||||
* adjusted by relocations. Currently supported values are:
|
||||
* - BPF_FIELD_BYTE_OFFSET: field offset (in bytes);
|
||||
* - BPF_FIELD_EXISTS: field existence (1, if field exists; 0, otherwise);
|
||||
*/
|
||||
static inline int libbpf_err_errno(int ret)
|
||||
{
|
||||
if (libbpf_mode & LIBBPF_STRICT_DIRECT_ERRS)
|
||||
/* errno is already assumed to be set on error */
|
||||
return ret < 0 ? -errno : ret;
|
||||
enum bpf_field_info_kind {
|
||||
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
||||
BPF_FIELD_BYTE_SIZE = 1,
|
||||
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
||||
BPF_FIELD_SIGNED = 3,
|
||||
BPF_FIELD_LSHIFT_U64 = 4,
|
||||
BPF_FIELD_RSHIFT_U64 = 5,
|
||||
};
|
||||
|
||||
/* legacy: on error return -1 directly and don't touch errno */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* handle error for pointer-returning APIs, err is assumed to be < 0 always */
|
||||
static inline void *libbpf_err_ptr(int err)
|
||||
{
|
||||
/* set errno on error, this doesn't break anything */
|
||||
errno = -err;
|
||||
|
||||
if (libbpf_mode & LIBBPF_STRICT_CLEAN_PTRS)
|
||||
return NULL;
|
||||
|
||||
/* legacy: encode err as ptr */
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* handle pointer-returning APIs' error handling */
|
||||
static inline void *libbpf_ptr(void *ret)
|
||||
{
|
||||
/* set errno on error, this doesn't break anything */
|
||||
if (IS_ERR(ret))
|
||||
errno = -PTR_ERR(ret);
|
||||
|
||||
if (libbpf_mode & LIBBPF_STRICT_CLEAN_PTRS)
|
||||
return IS_ERR(ret) ? NULL : ret;
|
||||
|
||||
/* legacy: pass-through original pointer */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool str_is_empty(const char *s)
|
||||
{
|
||||
return !s || !s[0];
|
||||
}
|
||||
|
||||
static inline bool is_ldimm64_insn(struct bpf_insn *insn)
|
||||
{
|
||||
return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
||||
}
|
||||
|
||||
/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2
|
||||
* Takes ownership of the fd passed in, and closes it if calling
|
||||
* fcntl(fd, F_DUPFD_CLOEXEC, 3).
|
||||
/* The minimum bpf_field_reloc checked by the loader
|
||||
*
|
||||
* Field relocation captures the following data:
|
||||
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
||||
* its insn->imm field to be relocated with actual field info;
|
||||
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
||||
* field;
|
||||
* - access_str_off - offset into corresponding .BTF string section. String
|
||||
* itself encodes an accessed field using a sequence of field and array
|
||||
* indicies, separated by colon (:). It's conceptually very close to LLVM's
|
||||
* getelementptr ([0]) instruction's arguments for identifying offset to
|
||||
* a field.
|
||||
*
|
||||
* Example to provide a better feel.
|
||||
*
|
||||
* struct sample {
|
||||
* int a;
|
||||
* struct {
|
||||
* int b[10];
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* struct sample *s = ...;
|
||||
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||
* // b is field #0 inside anon struct, accessing elem #5)
|
||||
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||
*
|
||||
* type_id for all relocs in this example will capture BTF type id of
|
||||
* `struct sample`.
|
||||
*
|
||||
* Such relocation is emitted when using __builtin_preserve_access_index()
|
||||
* Clang built-in, passing expression that captures field address, e.g.:
|
||||
*
|
||||
* bpf_probe_read(&dst, sizeof(dst),
|
||||
* __builtin_preserve_access_index(&src->a.b.c));
|
||||
*
|
||||
* In this case Clang will emit field relocation recording necessary data to
|
||||
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
||||
*
|
||||
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
||||
*/
|
||||
static inline int ensure_good_fd(int fd)
|
||||
{
|
||||
int old_fd = fd, saved_errno;
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
if (fd < 3) {
|
||||
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
saved_errno = errno;
|
||||
close(old_fd);
|
||||
if (fd < 0) {
|
||||
pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
||||
errno = saved_errno;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* The following two functions are exposed to bpftool */
|
||||
int bpf_core_add_cands(struct bpf_core_cand *local_cand,
|
||||
size_t local_essent_len,
|
||||
const struct btf *targ_btf,
|
||||
const char *targ_btf_name,
|
||||
int targ_start_id,
|
||||
struct bpf_core_cand_list *cands);
|
||||
void bpf_core_free_cands(struct bpf_core_cand_list *cands);
|
||||
|
||||
struct usdt_manager *usdt_manager_new(struct bpf_object *obj);
|
||||
void usdt_manager_free(struct usdt_manager *man);
|
||||
struct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man,
|
||||
const struct bpf_program *prog,
|
||||
pid_t pid, const char *path,
|
||||
const char *usdt_provider, const char *usdt_name,
|
||||
__u64 usdt_cookie);
|
||||
struct bpf_field_reloc {
|
||||
__u32 insn_off;
|
||||
__u32 type_id;
|
||||
__u32 access_str_off;
|
||||
enum bpf_field_info_kind kind;
|
||||
};
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
|
||||
/*
|
||||
* Libbpf legacy APIs (either discouraged or deprecated, as mentioned in [0])
|
||||
*
|
||||
* [0] https://docs.google.com/document/d/1UyjTZuPFWiPFyKk1tV5an11_iaRuec6U-ZESZ54nNTY
|
||||
*
|
||||
* Copyright (C) 2021 Facebook
|
||||
*/
|
||||
#ifndef __LIBBPF_LEGACY_BPF_H
|
||||
#define __LIBBPF_LEGACY_BPF_H
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "libbpf_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum libbpf_strict_mode {
|
||||
/* Turn on all supported strict features of libbpf to simulate libbpf
|
||||
* v1.0 behavior.
|
||||
* This will be the default behavior in libbpf v1.0.
|
||||
*/
|
||||
LIBBPF_STRICT_ALL = 0xffffffff,
|
||||
|
||||
/*
|
||||
* Disable any libbpf 1.0 behaviors. This is the default before libbpf
|
||||
* v1.0. It won't be supported anymore in v1.0, please update your
|
||||
* code so that it handles LIBBPF_STRICT_ALL mode before libbpf v1.0.
|
||||
*/
|
||||
LIBBPF_STRICT_NONE = 0x00,
|
||||
/*
|
||||
* Return NULL pointers on error, not ERR_PTR(err).
|
||||
* Additionally, libbpf also always sets errno to corresponding Exx
|
||||
* (positive) error code.
|
||||
*/
|
||||
LIBBPF_STRICT_CLEAN_PTRS = 0x01,
|
||||
/*
|
||||
* Return actual error codes from low-level APIs directly, not just -1.
|
||||
* Additionally, libbpf also always sets errno to corresponding Exx
|
||||
* (positive) error code.
|
||||
*/
|
||||
LIBBPF_STRICT_DIRECT_ERRS = 0x02,
|
||||
/*
|
||||
* Enforce strict BPF program section (SEC()) names.
|
||||
* E.g., while prefiously SEC("xdp_whatever") or SEC("perf_event_blah") were
|
||||
* allowed, with LIBBPF_STRICT_SEC_PREFIX this will become
|
||||
* unrecognized by libbpf and would have to be just SEC("xdp") and
|
||||
* SEC("xdp") and SEC("perf_event").
|
||||
*
|
||||
* Note, in this mode the program pin path will be based on the
|
||||
* function name instead of section name.
|
||||
*
|
||||
* Additionally, routines in the .text section are always considered
|
||||
* sub-programs. Legacy behavior allows for a single routine in .text
|
||||
* to be a program.
|
||||
*/
|
||||
LIBBPF_STRICT_SEC_NAME = 0x04,
|
||||
/*
|
||||
* Disable the global 'bpf_objects_list'. Maintaining this list adds
|
||||
* a race condition to bpf_object__open() and bpf_object__close().
|
||||
* Clients can maintain it on their own if it is valuable for them.
|
||||
*/
|
||||
LIBBPF_STRICT_NO_OBJECT_LIST = 0x08,
|
||||
/*
|
||||
* Automatically bump RLIMIT_MEMLOCK using setrlimit() before the
|
||||
* 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 overriden with libbpf_set_memlock_rlim_max() API.
|
||||
* Note that libbpf_set_memlock_rlim_max() needs to be called before
|
||||
* the very first bpf_prog_load(), bpf_map_create() or bpf_object__load()
|
||||
* operation.
|
||||
*/
|
||||
LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK = 0x10,
|
||||
/*
|
||||
* Error out on any SEC("maps") map definition, which are deprecated
|
||||
* in favor of BTF-defined map definitions in SEC(".maps").
|
||||
*/
|
||||
LIBBPF_STRICT_MAP_DEFINITIONS = 0x20,
|
||||
|
||||
__LIBBPF_STRICT_LAST,
|
||||
};
|
||||
|
||||
LIBBPF_API int libbpf_set_strict_mode(enum libbpf_strict_mode mode);
|
||||
|
||||
#define DECLARE_LIBBPF_OPTS LIBBPF_OPTS
|
||||
|
||||
/* "Discouraged" APIs which don't follow consistent libbpf naming patterns.
|
||||
* They are normally a trivial aliases or wrappers for proper APIs and are
|
||||
* left to minimize unnecessary disruption for users of libbpf. But they
|
||||
* shouldn't be used going forward.
|
||||
*/
|
||||
|
||||
struct bpf_program;
|
||||
struct bpf_map;
|
||||
struct btf;
|
||||
struct btf_ext;
|
||||
|
||||
LIBBPF_API enum bpf_prog_type bpf_program__get_type(const struct bpf_program *prog);
|
||||
LIBBPF_API enum bpf_attach_type bpf_program__get_expected_attach_type(const struct bpf_program *prog);
|
||||
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
||||
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||
LIBBPF_API const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __LIBBPF_LEGACY_BPF_H */
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
static bool grep(const char *buffer, const char *pattern)
|
||||
{
|
||||
return !!strstr(buffer, pattern);
|
||||
@@ -33,7 +36,7 @@ static int get_vendor_id(int ifindex)
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
|
||||
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
@@ -48,65 +51,35 @@ static int get_vendor_id(int ifindex)
|
||||
return strtol(buf, NULL, 0);
|
||||
}
|
||||
|
||||
static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||
const struct bpf_insn *insns, size_t insns_cnt,
|
||||
char *log_buf, size_t log_buf_sz,
|
||||
__u32 ifindex)
|
||||
static int get_kernel_version(void)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.log_buf = log_buf,
|
||||
.log_size = log_buf_sz,
|
||||
.log_level = log_buf ? 1 : 0,
|
||||
.prog_ifindex = ifindex,
|
||||
);
|
||||
int fd, err, exp_err = 0;
|
||||
const char *exp_msg = NULL;
|
||||
char buf[4096];
|
||||
int version, subversion, patchlevel;
|
||||
struct utsname utsn;
|
||||
|
||||
/* Return 0 on failure, and attempt to probe with empty kversion */
|
||||
if (uname(&utsn))
|
||||
return 0;
|
||||
|
||||
if (sscanf(utsn.release, "%d.%d.%d",
|
||||
&version, &subversion, &patchlevel) != 3)
|
||||
return 0;
|
||||
|
||||
return (version << 16) + (subversion << 8) + patchlevel;
|
||||
}
|
||||
|
||||
static void
|
||||
probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
||||
size_t insns_cnt, char *buf, size_t buf_len, __u32 ifindex)
|
||||
{
|
||||
struct bpf_load_program_attr xattr = {};
|
||||
int fd;
|
||||
|
||||
switch (prog_type) {
|
||||
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
|
||||
opts.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
||||
break;
|
||||
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||
opts.expected_attach_type = BPF_CGROUP_GETSOCKOPT;
|
||||
break;
|
||||
case BPF_PROG_TYPE_SK_LOOKUP:
|
||||
opts.expected_attach_type = BPF_SK_LOOKUP;
|
||||
xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
||||
break;
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
opts.kern_version = get_kernel_version();
|
||||
break;
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
opts.expected_attach_type = BPF_LIRC_MODE2;
|
||||
break;
|
||||
case BPF_PROG_TYPE_TRACING:
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
opts.log_buf = buf;
|
||||
opts.log_size = sizeof(buf);
|
||||
opts.log_level = 1;
|
||||
if (prog_type == BPF_PROG_TYPE_TRACING)
|
||||
opts.expected_attach_type = BPF_TRACE_FENTRY;
|
||||
else
|
||||
opts.expected_attach_type = BPF_MODIFY_RETURN;
|
||||
opts.attach_btf_id = 1;
|
||||
|
||||
exp_err = -EINVAL;
|
||||
exp_msg = "attach_btf_id 1 is not a function";
|
||||
break;
|
||||
case BPF_PROG_TYPE_EXT:
|
||||
opts.log_buf = buf;
|
||||
opts.log_size = sizeof(buf);
|
||||
opts.log_level = 1;
|
||||
opts.attach_btf_id = 1;
|
||||
|
||||
exp_err = -EINVAL;
|
||||
exp_msg = "Cannot replace kernel functions";
|
||||
break;
|
||||
case BPF_PROG_TYPE_SYSCALL:
|
||||
opts.prog_flags = BPF_F_SLEEPABLE;
|
||||
break;
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
exp_err = -524; /* -ENOTSUPP */
|
||||
xattr.kern_version = get_kernel_version();
|
||||
break;
|
||||
case BPF_PROG_TYPE_UNSPEC:
|
||||
case BPF_PROG_TYPE_SOCKET_FILTER:
|
||||
@@ -127,42 +100,28 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
|
||||
case BPF_PROG_TYPE_LWT_SEG6LOCAL:
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||
break;
|
||||
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||
case BPF_PROG_TYPE_TRACING:
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
case BPF_PROG_TYPE_EXT:
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
|
||||
err = -errno;
|
||||
xattr.prog_type = prog_type;
|
||||
xattr.insns = insns;
|
||||
xattr.insns_cnt = insns_cnt;
|
||||
xattr.license = "GPL";
|
||||
xattr.prog_ifindex = ifindex;
|
||||
|
||||
fd = bpf_load_program_xattr(&xattr, buf, buf_len);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (exp_err) {
|
||||
if (fd >= 0 || err != exp_err)
|
||||
return 0;
|
||||
if (exp_msg && !strstr(buf, exp_msg))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return fd >= 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN()
|
||||
};
|
||||
const size_t insn_cnt = ARRAY_SIZE(insns);
|
||||
int ret;
|
||||
|
||||
if (opts)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
ret = probe_prog_load(prog_type, insns, insn_cnt, NULL, 0, 0);
|
||||
return libbpf_err(ret);
|
||||
}
|
||||
|
||||
bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
|
||||
@@ -172,16 +131,12 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
|
||||
BPF_EXIT_INSN()
|
||||
};
|
||||
|
||||
/* prefer libbpf_probe_bpf_prog_type() unless offload is requested */
|
||||
if (ifindex == 0)
|
||||
return libbpf_probe_bpf_prog_type(prog_type, NULL) == 1;
|
||||
|
||||
if (ifindex && prog_type == BPF_PROG_TYPE_SCHED_CLS)
|
||||
/* nfp returns -EINVAL on exit(0) with TC offload */
|
||||
insns[0].imm = 2;
|
||||
|
||||
errno = 0;
|
||||
probe_prog_load(prog_type, insns, ARRAY_SIZE(insns), NULL, 0, ifindex);
|
||||
probe_load(prog_type, insns, ARRAY_SIZE(insns), NULL, 0, ifindex);
|
||||
|
||||
return errno != EINVAL && errno != EOPNOTSUPP;
|
||||
}
|
||||
@@ -209,13 +164,13 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
|
||||
memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
|
||||
|
||||
btf_fd = bpf_btf_load(raw_btf, btf_len, NULL);
|
||||
btf_fd = bpf_load_btf(raw_btf, btf_len, NULL, 0, false);
|
||||
|
||||
free(raw_btf);
|
||||
return btf_fd;
|
||||
}
|
||||
|
||||
static int load_local_storage_btf(void)
|
||||
static int load_sk_storage_btf(void)
|
||||
{
|
||||
const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";
|
||||
/* struct bpf_spin_lock {
|
||||
@@ -242,18 +197,17 @@ static int load_local_storage_btf(void)
|
||||
strs, sizeof(strs));
|
||||
}
|
||||
|
||||
static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
|
||||
bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||
int key_size, value_size, max_entries;
|
||||
int key_size, value_size, max_entries, map_flags;
|
||||
__u32 btf_key_type_id = 0, btf_value_type_id = 0;
|
||||
int fd = -1, btf_fd = -1, fd_inner = -1, exp_err = 0, err;
|
||||
|
||||
opts.map_ifindex = ifindex;
|
||||
struct bpf_create_map_attr attr = {};
|
||||
int fd = -1, btf_fd = -1, fd_inner;
|
||||
|
||||
key_size = sizeof(__u32);
|
||||
value_size = sizeof(__u32);
|
||||
max_entries = 1;
|
||||
map_flags = 0;
|
||||
|
||||
switch (map_type) {
|
||||
case BPF_MAP_TYPE_STACK_TRACE:
|
||||
@@ -262,7 +216,7 @@ static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
|
||||
case BPF_MAP_TYPE_LPM_TRIE:
|
||||
key_size = sizeof(__u64);
|
||||
value_size = sizeof(__u64);
|
||||
opts.map_flags = BPF_F_NO_PREALLOC;
|
||||
map_flags = BPF_F_NO_PREALLOC;
|
||||
break;
|
||||
case BPF_MAP_TYPE_CGROUP_STORAGE:
|
||||
case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
|
||||
@@ -275,31 +229,21 @@ static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
|
||||
key_size = 0;
|
||||
break;
|
||||
case BPF_MAP_TYPE_SK_STORAGE:
|
||||
case BPF_MAP_TYPE_INODE_STORAGE:
|
||||
case BPF_MAP_TYPE_TASK_STORAGE:
|
||||
btf_key_type_id = 1;
|
||||
btf_value_type_id = 3;
|
||||
value_size = 8;
|
||||
max_entries = 0;
|
||||
opts.map_flags = BPF_F_NO_PREALLOC;
|
||||
btf_fd = load_local_storage_btf();
|
||||
map_flags = BPF_F_NO_PREALLOC;
|
||||
btf_fd = load_sk_storage_btf();
|
||||
if (btf_fd < 0)
|
||||
return btf_fd;
|
||||
return false;
|
||||
break;
|
||||
case BPF_MAP_TYPE_RINGBUF:
|
||||
key_size = 0;
|
||||
value_size = 0;
|
||||
max_entries = 4096;
|
||||
break;
|
||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||
/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
|
||||
opts.btf_vmlinux_value_type_id = 1;
|
||||
exp_err = -524; /* -ENOTSUPP */
|
||||
break;
|
||||
case BPF_MAP_TYPE_BLOOM_FILTER:
|
||||
key_size = 0;
|
||||
max_entries = 1;
|
||||
break;
|
||||
case BPF_MAP_TYPE_UNSPEC:
|
||||
case BPF_MAP_TYPE_HASH:
|
||||
case BPF_MAP_TYPE_ARRAY:
|
||||
case BPF_MAP_TYPE_PROG_ARRAY:
|
||||
@@ -318,10 +262,9 @@ static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
|
||||
case BPF_MAP_TYPE_XSKMAP:
|
||||
case BPF_MAP_TYPE_SOCKHASH:
|
||||
case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
|
||||
break;
|
||||
case BPF_MAP_TYPE_UNSPEC:
|
||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
|
||||
@@ -330,102 +273,37 @@ static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
|
||||
* map-in-map for offload
|
||||
*/
|
||||
if (ifindex)
|
||||
goto cleanup;
|
||||
return false;
|
||||
|
||||
fd_inner = bpf_map_create(BPF_MAP_TYPE_HASH, NULL,
|
||||
sizeof(__u32), sizeof(__u32), 1, NULL);
|
||||
fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
|
||||
sizeof(__u32), sizeof(__u32), 1, 0);
|
||||
if (fd_inner < 0)
|
||||
goto cleanup;
|
||||
return false;
|
||||
fd = bpf_create_map_in_map(map_type, NULL, sizeof(__u32),
|
||||
fd_inner, 1, 0);
|
||||
close(fd_inner);
|
||||
} else {
|
||||
/* Note: No other restriction on map type probes for offload */
|
||||
attr.map_type = map_type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.max_entries = max_entries;
|
||||
attr.map_flags = map_flags;
|
||||
attr.map_ifindex = ifindex;
|
||||
if (btf_fd >= 0) {
|
||||
attr.btf_fd = btf_fd;
|
||||
attr.btf_key_type_id = btf_key_type_id;
|
||||
attr.btf_value_type_id = btf_value_type_id;
|
||||
}
|
||||
|
||||
opts.inner_map_fd = fd_inner;
|
||||
fd = bpf_create_map_xattr(&attr);
|
||||
}
|
||||
|
||||
if (btf_fd >= 0) {
|
||||
opts.btf_fd = btf_fd;
|
||||
opts.btf_key_type_id = btf_key_type_id;
|
||||
opts.btf_value_type_id = btf_value_type_id;
|
||||
}
|
||||
|
||||
fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);
|
||||
err = -errno;
|
||||
|
||||
cleanup:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (fd_inner >= 0)
|
||||
close(fd_inner);
|
||||
if (btf_fd >= 0)
|
||||
close(btf_fd);
|
||||
|
||||
if (exp_err)
|
||||
return fd < 0 && err == exp_err ? 1 : 0;
|
||||
else
|
||||
return fd >= 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
int libbpf_probe_bpf_map_type(enum bpf_map_type map_type, const void *opts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (opts)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
ret = probe_map_create(map_type, 0);
|
||||
return libbpf_err(ret);
|
||||
}
|
||||
|
||||
bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
||||
{
|
||||
return probe_map_create(map_type, ifindex) == 1;
|
||||
}
|
||||
|
||||
int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
|
||||
const void *opts)
|
||||
{
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_EMIT_CALL((__u32)helper_id),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
const size_t insn_cnt = ARRAY_SIZE(insns);
|
||||
char buf[4096];
|
||||
int ret;
|
||||
|
||||
if (opts)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
/* we can't successfully load all prog types to check for BPF helper
|
||||
* support, so bail out with -EOPNOTSUPP error
|
||||
*/
|
||||
switch (prog_type) {
|
||||
case BPF_PROG_TYPE_TRACING:
|
||||
case BPF_PROG_TYPE_EXT:
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
ret = probe_prog_load(prog_type, insns, insn_cnt, buf, sizeof(buf), 0);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
|
||||
/* If BPF verifier doesn't recognize BPF helper ID (enum bpf_func_id)
|
||||
* at all, it will emit something like "invalid func unknown#181".
|
||||
* If BPF verifier recognizes BPF helper but it's not supported for
|
||||
* given BPF program type, it will emit "unknown func bpf_sys_bpf#166".
|
||||
* In both cases, provided combination of BPF program type and BPF
|
||||
* helper is not supported by the kernel.
|
||||
* In all other cases, probe_prog_load() above will either succeed (e.g.,
|
||||
* because BPF helper happens to accept no input arguments or it
|
||||
* accepts one input argument and initial PTR_TO_CTX is fine for
|
||||
* that), or we'll get some more specific BPF verifier error about
|
||||
* some unsatisfied conditions.
|
||||
*/
|
||||
if (ret == 0 && (strstr(buf, "invalid func ") || strstr(buf, "unknown func ")))
|
||||
return 0;
|
||||
return 1; /* assume supported */
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
|
||||
@@ -438,7 +316,8 @@ bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
|
||||
char buf[4096] = {};
|
||||
bool res;
|
||||
|
||||
probe_prog_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf), ifindex);
|
||||
probe_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf),
|
||||
ifindex);
|
||||
res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
|
||||
|
||||
if (ifindex) {
|
||||
@@ -470,8 +349,8 @@ bool bpf_probe_large_insn_limit(__u32 ifindex)
|
||||
insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
|
||||
|
||||
errno = 0;
|
||||
probe_prog_load(BPF_PROG_TYPE_SCHED_CLS, insns, ARRAY_SIZE(insns), NULL, 0,
|
||||
ifindex);
|
||||
probe_load(BPF_PROG_TYPE_SCHED_CLS, insns, ARRAY_SIZE(insns), NULL, 0,
|
||||
ifindex);
|
||||
|
||||
return errno != E2BIG && errno != EINVAL;
|
||||
}
|
||||
|
||||
47
src/libbpf_util.h
Normal file
47
src/libbpf_util.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2019 Facebook */
|
||||
|
||||
#ifndef __LIBBPF_LIBBPF_UTIL_H
|
||||
#define __LIBBPF_LIBBPF_UTIL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Use these barrier functions instead of smp_[rw]mb() when they are
|
||||
* used in a libbpf header file. That way they can be built into the
|
||||
* application that uses libbpf.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# define libbpf_smp_rmb() asm volatile("" : : : "memory")
|
||||
# define libbpf_smp_wmb() asm volatile("" : : : "memory")
|
||||
# define libbpf_smp_mb() \
|
||||
asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc")
|
||||
/* Hinders stores to be observed before older loads. */
|
||||
# define libbpf_smp_rwmb() asm volatile("" : : : "memory")
|
||||
#elif defined(__aarch64__)
|
||||
# define libbpf_smp_rmb() asm volatile("dmb ishld" : : : "memory")
|
||||
# define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory")
|
||||
# define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory")
|
||||
# define libbpf_smp_rwmb() libbpf_smp_mb()
|
||||
#elif defined(__arm__)
|
||||
/* These are only valid for armv7 and above */
|
||||
# define libbpf_smp_rmb() asm volatile("dmb ish" : : : "memory")
|
||||
# define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory")
|
||||
# define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory")
|
||||
# define libbpf_smp_rwmb() libbpf_smp_mb()
|
||||
#else
|
||||
/* Architecture missing native barrier functions. */
|
||||
# define libbpf_smp_rmb() __sync_synchronize()
|
||||
# define libbpf_smp_wmb() __sync_synchronize()
|
||||
# define libbpf_smp_mb() __sync_synchronize()
|
||||
# define libbpf_smp_rwmb() __sync_synchronize()
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (C) 2021 Facebook */
|
||||
#ifndef __LIBBPF_VERSION_H
|
||||
#define __LIBBPF_VERSION_H
|
||||
|
||||
#define LIBBPF_MAJOR_VERSION 0
|
||||
#define LIBBPF_MINOR_VERSION 8
|
||||
|
||||
#endif /* __LIBBPF_VERSION_H */
|
||||
2903
src/linker.c
2903
src/linker.c
File diff suppressed because it is too large
Load Diff
828
src/netlink.c
828
src/netlink.c
@@ -4,10 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
@@ -18,12 +15,13 @@
|
||||
#include "libbpf_internal.h"
|
||||
#include "nlattr.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
|
||||
|
||||
typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
|
||||
void *cookie);
|
||||
|
||||
@@ -33,7 +31,7 @@ struct xdp_id_md {
|
||||
struct xdp_link_info info;
|
||||
};
|
||||
|
||||
static int libbpf_netlink_open(__u32 *nl_pid)
|
||||
int libbpf_netlink_open(__u32 *nl_pid)
|
||||
{
|
||||
struct sockaddr_nl sa;
|
||||
socklen_t addrlen;
|
||||
@@ -43,7 +41,7 @@ static int libbpf_netlink_open(__u32 *nl_pid)
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
|
||||
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (sock < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -76,86 +74,28 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void libbpf_netlink_close(int sock)
|
||||
static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
||||
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
|
||||
void *cookie)
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
|
||||
enum {
|
||||
NL_CONT,
|
||||
NL_NEXT,
|
||||
NL_DONE,
|
||||
};
|
||||
|
||||
static int netlink_recvmsg(int sock, struct msghdr *mhdr, int flags)
|
||||
{
|
||||
int len;
|
||||
|
||||
do {
|
||||
len = recvmsg(sock, mhdr, flags);
|
||||
} while (len < 0 && (errno == EINTR || errno == EAGAIN));
|
||||
|
||||
if (len < 0)
|
||||
return -errno;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int alloc_iov(struct iovec *iov, int len)
|
||||
{
|
||||
void *nbuf;
|
||||
|
||||
nbuf = realloc(iov->iov_base, len);
|
||||
if (!nbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
iov->iov_base = nbuf;
|
||||
iov->iov_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
||||
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
|
||||
void *cookie)
|
||||
{
|
||||
struct iovec iov = {};
|
||||
struct msghdr mhdr = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
bool multipart = true;
|
||||
struct nlmsgerr *err;
|
||||
struct nlmsghdr *nh;
|
||||
char buf[4096];
|
||||
int len, ret;
|
||||
|
||||
ret = alloc_iov(&iov, 4096);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
while (multipart) {
|
||||
start:
|
||||
multipart = false;
|
||||
len = netlink_recvmsg(sock, &mhdr, MSG_PEEK | MSG_TRUNC);
|
||||
len = recv(sock, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
ret = len;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (len > iov.iov_len) {
|
||||
ret = alloc_iov(&iov, len);
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
len = netlink_recvmsg(sock, &mhdr, 0);
|
||||
if (len < 0) {
|
||||
ret = len;
|
||||
ret = -errno;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
for (nh = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(nh, len);
|
||||
for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
|
||||
nh = NLMSG_NEXT(nh, len)) {
|
||||
if (nh->nlmsg_pid != nl_pid) {
|
||||
ret = -LIBBPF_ERRNO__WRNGPID;
|
||||
@@ -176,141 +116,111 @@ start:
|
||||
libbpf_nla_dump_errormsg(nh);
|
||||
goto done;
|
||||
case NLMSG_DONE:
|
||||
ret = 0;
|
||||
goto done;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (_fn) {
|
||||
ret = _fn(nh, fn, cookie);
|
||||
switch (ret) {
|
||||
case NL_CONT:
|
||||
break;
|
||||
case NL_NEXT:
|
||||
goto start;
|
||||
case NL_DONE:
|
||||
ret = 0;
|
||||
goto done;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
done:
|
||||
free(iov.iov_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
|
||||
__dump_nlmsg_t parse_msg,
|
||||
libbpf_dump_nlmsg_t parse_attr,
|
||||
void *cookie)
|
||||
{
|
||||
__u32 nl_pid = 0;
|
||||
int sock, ret;
|
||||
|
||||
sock = libbpf_netlink_open(&nl_pid);
|
||||
if (sock < 0)
|
||||
return sock;
|
||||
|
||||
req->nh.nlmsg_pid = 0;
|
||||
req->nh.nlmsg_seq = time(NULL);
|
||||
|
||||
if (send(sock, req, req->nh.nlmsg_len, 0) < 0) {
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = libbpf_netlink_recv(sock, nl_pid, req->nh.nlmsg_seq,
|
||||
parse_msg, parse_attr, cookie);
|
||||
out:
|
||||
libbpf_netlink_close(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
||||
__u32 flags)
|
||||
{
|
||||
struct nlattr *nla;
|
||||
int ret;
|
||||
struct libbpf_nla_req req;
|
||||
int sock, seq = 0, ret;
|
||||
struct nlattr *nla, *nla_xdp;
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
struct ifinfomsg ifinfo;
|
||||
char attrbuf[64];
|
||||
} req;
|
||||
__u32 nl_pid = 0;
|
||||
|
||||
sock = libbpf_netlink_open(&nl_pid);
|
||||
if (sock < 0)
|
||||
return sock;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.nh.nlmsg_type = RTM_SETLINK;
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.nh.nlmsg_type = RTM_SETLINK;
|
||||
req.nh.nlmsg_pid = 0;
|
||||
req.nh.nlmsg_seq = ++seq;
|
||||
req.ifinfo.ifi_family = AF_UNSPEC;
|
||||
req.ifinfo.ifi_index = ifindex;
|
||||
req.ifinfo.ifi_index = ifindex;
|
||||
|
||||
nla = nlattr_begin_nested(&req, IFLA_XDP);
|
||||
if (!nla)
|
||||
return -EMSGSIZE;
|
||||
ret = nlattr_add(&req, IFLA_XDP_FD, &fd, sizeof(fd));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* started nested attribute for XDP */
|
||||
nla = (struct nlattr *)(((char *)&req)
|
||||
+ NLMSG_ALIGN(req.nh.nlmsg_len));
|
||||
nla->nla_type = NLA_F_NESTED | IFLA_XDP;
|
||||
nla->nla_len = NLA_HDRLEN;
|
||||
|
||||
/* add XDP fd */
|
||||
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
|
||||
nla_xdp->nla_type = IFLA_XDP_FD;
|
||||
nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
|
||||
memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
|
||||
nla->nla_len += nla_xdp->nla_len;
|
||||
|
||||
/* if user passed in any flags, add those too */
|
||||
if (flags) {
|
||||
ret = nlattr_add(&req, IFLA_XDP_FLAGS, &flags, sizeof(flags));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
|
||||
nla_xdp->nla_type = IFLA_XDP_FLAGS;
|
||||
nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
|
||||
memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
|
||||
nla->nla_len += nla_xdp->nla_len;
|
||||
}
|
||||
|
||||
if (flags & XDP_FLAGS_REPLACE) {
|
||||
ret = nlattr_add(&req, IFLA_XDP_EXPECTED_FD, &old_fd,
|
||||
sizeof(old_fd));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
|
||||
nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD;
|
||||
nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd);
|
||||
memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd));
|
||||
nla->nla_len += nla_xdp->nla_len;
|
||||
}
|
||||
nlattr_end_nested(&req, nla);
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
}
|
||||
req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
|
||||
|
||||
int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts)
|
||||
{
|
||||
int old_prog_fd, err;
|
||||
if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
|
||||
ret = -errno;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_xdp_attach_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||
if (old_prog_fd)
|
||||
flags |= XDP_FLAGS_REPLACE;
|
||||
else
|
||||
old_prog_fd = -1;
|
||||
|
||||
err = __bpf_set_link_xdp_fd_replace(ifindex, prog_fd, old_prog_fd, flags);
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
int bpf_xdp_detach(int ifindex, __u32 flags, const struct bpf_xdp_attach_opts *opts)
|
||||
{
|
||||
return bpf_xdp_attach(ifindex, -1, flags, opts);
|
||||
cleanup:
|
||||
close(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
|
||||
const struct bpf_xdp_set_link_opts *opts)
|
||||
{
|
||||
int old_fd = -1, ret;
|
||||
int old_fd = -1;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_xdp_set_link_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
return -EINVAL;
|
||||
|
||||
if (OPTS_HAS(opts, old_fd)) {
|
||||
old_fd = OPTS_GET(opts, old_fd, -1);
|
||||
flags |= XDP_FLAGS_REPLACE;
|
||||
}
|
||||
|
||||
ret = __bpf_set_link_xdp_fd_replace(ifindex, fd, old_fd, flags);
|
||||
return libbpf_err(ret);
|
||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd,
|
||||
old_fd,
|
||||
flags);
|
||||
}
|
||||
|
||||
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
|
||||
return libbpf_err(ret);
|
||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
|
||||
}
|
||||
|
||||
static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
||||
@@ -322,7 +232,6 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
||||
|
||||
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
|
||||
attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
|
||||
|
||||
if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
|
||||
return -LIBBPF_ERRNO__NLPARSE;
|
||||
|
||||
@@ -374,485 +283,206 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts)
|
||||
{
|
||||
struct libbpf_nla_req req = {
|
||||
.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.nh.nlmsg_type = RTM_GETLINK,
|
||||
.nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.ifinfo.ifi_family = AF_PACKET,
|
||||
};
|
||||
struct xdp_id_md xdp_id = {};
|
||||
int err;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_xdp_query_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (xdp_flags & ~XDP_FLAGS_MASK)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
/* Check whether the single {HW,DRV,SKB} mode is set */
|
||||
xdp_flags &= XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE;
|
||||
if (xdp_flags & (xdp_flags - 1))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
xdp_id.ifindex = ifindex;
|
||||
xdp_id.flags = xdp_flags;
|
||||
|
||||
err = libbpf_netlink_send_recv(&req, __dump_link_nlmsg,
|
||||
get_xdp_info, &xdp_id);
|
||||
if (err)
|
||||
return libbpf_err(err);
|
||||
|
||||
OPTS_SET(opts, prog_id, xdp_id.info.prog_id);
|
||||
OPTS_SET(opts, drv_prog_id, xdp_id.info.drv_prog_id);
|
||||
OPTS_SET(opts, hw_prog_id, xdp_id.info.hw_prog_id);
|
||||
OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id);
|
||||
OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||
size_t info_size, __u32 flags)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_xdp_query_opts, opts);
|
||||
size_t sz;
|
||||
int err;
|
||||
struct xdp_id_md xdp_id = {};
|
||||
int sock, ret;
|
||||
__u32 nl_pid = 0;
|
||||
__u32 mask;
|
||||
|
||||
if (!info_size)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (flags & ~XDP_FLAGS_MASK || !info_size)
|
||||
return -EINVAL;
|
||||
|
||||
err = bpf_xdp_query(ifindex, flags, &opts);
|
||||
if (err)
|
||||
return libbpf_err(err);
|
||||
/* Check whether the single {HW,DRV,SKB} mode is set */
|
||||
flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
|
||||
mask = flags - 1;
|
||||
if (flags && flags & mask)
|
||||
return -EINVAL;
|
||||
|
||||
/* struct xdp_link_info field layout matches struct bpf_xdp_query_opts
|
||||
* layout after sz field
|
||||
*/
|
||||
sz = min(info_size, offsetofend(struct xdp_link_info, attach_mode));
|
||||
memcpy(info, &opts.prog_id, sz);
|
||||
memset((void *)info + sz, 0, info_size - sz);
|
||||
sock = libbpf_netlink_open(&nl_pid);
|
||||
if (sock < 0)
|
||||
return sock;
|
||||
|
||||
return 0;
|
||||
xdp_id.ifindex = ifindex;
|
||||
xdp_id.flags = flags;
|
||||
|
||||
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
|
||||
if (!ret) {
|
||||
size_t sz = min(info_size, sizeof(xdp_id.info));
|
||||
|
||||
memcpy(info, &xdp_id.info, sz);
|
||||
memset((void *) info + sz, 0, info_size - sz);
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_xdp_query_id(int ifindex, int flags, __u32 *prog_id)
|
||||
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_xdp_query_opts, opts);
|
||||
int ret;
|
||||
|
||||
ret = bpf_xdp_query(ifindex, flags, &opts);
|
||||
if (ret)
|
||||
return libbpf_err(ret);
|
||||
|
||||
flags &= XDP_FLAGS_MODES;
|
||||
|
||||
if (opts.attach_mode != XDP_ATTACHED_MULTI && !flags)
|
||||
*prog_id = opts.prog_id;
|
||||
else if (flags & XDP_FLAGS_DRV_MODE)
|
||||
*prog_id = opts.drv_prog_id;
|
||||
else if (flags & XDP_FLAGS_HW_MODE)
|
||||
*prog_id = opts.hw_prog_id;
|
||||
else if (flags & XDP_FLAGS_SKB_MODE)
|
||||
*prog_id = opts.skb_prog_id;
|
||||
else
|
||||
*prog_id = 0;
|
||||
if (info->attach_mode != XDP_ATTACHED_MULTI && !flags)
|
||||
return info->prog_id;
|
||||
if (flags & XDP_FLAGS_DRV_MODE)
|
||||
return info->drv_prog_id;
|
||||
if (flags & XDP_FLAGS_HW_MODE)
|
||||
return info->hw_prog_id;
|
||||
if (flags & XDP_FLAGS_SKB_MODE)
|
||||
return info->skb_prog_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
|
||||
{
|
||||
return bpf_xdp_query_id(ifindex, flags, prog_id);
|
||||
}
|
||||
|
||||
typedef int (*qdisc_config_t)(struct libbpf_nla_req *req);
|
||||
|
||||
static int clsact_config(struct libbpf_nla_req *req)
|
||||
{
|
||||
req->tc.tcm_parent = TC_H_CLSACT;
|
||||
req->tc.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
|
||||
|
||||
return nlattr_add(req, TCA_KIND, "clsact", sizeof("clsact"));
|
||||
}
|
||||
|
||||
static int attach_point_to_config(struct bpf_tc_hook *hook,
|
||||
qdisc_config_t *config)
|
||||
{
|
||||
switch (OPTS_GET(hook, attach_point, 0)) {
|
||||
case BPF_TC_INGRESS:
|
||||
case BPF_TC_EGRESS:
|
||||
case BPF_TC_INGRESS | BPF_TC_EGRESS:
|
||||
if (OPTS_GET(hook, parent, 0))
|
||||
return -EINVAL;
|
||||
*config = &clsact_config;
|
||||
return 0;
|
||||
case BPF_TC_CUSTOM:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int tc_get_tcm_parent(enum bpf_tc_attach_point attach_point,
|
||||
__u32 *parent)
|
||||
{
|
||||
switch (attach_point) {
|
||||
case BPF_TC_INGRESS:
|
||||
case BPF_TC_EGRESS:
|
||||
if (*parent)
|
||||
return -EINVAL;
|
||||
*parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
attach_point == BPF_TC_INGRESS ?
|
||||
TC_H_MIN_INGRESS : TC_H_MIN_EGRESS);
|
||||
break;
|
||||
case BPF_TC_CUSTOM:
|
||||
if (!*parent)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc_qdisc_modify(struct bpf_tc_hook *hook, int cmd, int flags)
|
||||
{
|
||||
qdisc_config_t config;
|
||||
int ret;
|
||||
struct libbpf_nla_req req;
|
||||
|
||||
ret = attach_point_to_config(hook, &config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
|
||||
req.nh.nlmsg_type = cmd;
|
||||
req.tc.tcm_family = AF_UNSPEC;
|
||||
req.tc.tcm_ifindex = OPTS_GET(hook, ifindex, 0);
|
||||
|
||||
ret = config(&req);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int tc_qdisc_create_excl(struct bpf_tc_hook *hook)
|
||||
{
|
||||
return tc_qdisc_modify(hook, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL);
|
||||
}
|
||||
|
||||
static int tc_qdisc_delete(struct bpf_tc_hook *hook)
|
||||
{
|
||||
return tc_qdisc_modify(hook, RTM_DELQDISC, 0);
|
||||
}
|
||||
|
||||
int bpf_tc_hook_create(struct bpf_tc_hook *hook)
|
||||
{
|
||||
struct xdp_link_info info;
|
||||
int ret;
|
||||
|
||||
if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
|
||||
OPTS_GET(hook, ifindex, 0) <= 0)
|
||||
return libbpf_err(-EINVAL);
|
||||
ret = bpf_get_link_xdp_info(ifindex, &info, sizeof(info), flags);
|
||||
if (!ret)
|
||||
*prog_id = get_xdp_id(&info, flags);
|
||||
|
||||
ret = tc_qdisc_create_excl(hook);
|
||||
return libbpf_err(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||
const struct bpf_tc_opts *opts,
|
||||
const bool flush);
|
||||
|
||||
int bpf_tc_hook_destroy(struct bpf_tc_hook *hook)
|
||||
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
|
||||
{
|
||||
if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
|
||||
OPTS_GET(hook, ifindex, 0) <= 0)
|
||||
return libbpf_err(-EINVAL);
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct ifinfomsg ifm;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.nlh.nlmsg_type = RTM_GETLINK,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.ifm.ifi_family = AF_PACKET,
|
||||
};
|
||||
int seq = time(NULL);
|
||||
|
||||
switch (OPTS_GET(hook, attach_point, 0)) {
|
||||
case BPF_TC_INGRESS:
|
||||
case BPF_TC_EGRESS:
|
||||
return libbpf_err(__bpf_tc_detach(hook, NULL, true));
|
||||
case BPF_TC_INGRESS | BPF_TC_EGRESS:
|
||||
return libbpf_err(tc_qdisc_delete(hook));
|
||||
case BPF_TC_CUSTOM:
|
||||
return libbpf_err(-EOPNOTSUPP);
|
||||
default:
|
||||
return libbpf_err(-EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
struct bpf_cb_ctx {
|
||||
struct bpf_tc_opts *opts;
|
||||
bool processed;
|
||||
};
|
||||
|
||||
static int __get_tc_info(void *cookie, struct tcmsg *tc, struct nlattr **tb,
|
||||
bool unicast)
|
||||
{
|
||||
struct nlattr *tbb[TCA_BPF_MAX + 1];
|
||||
struct bpf_cb_ctx *info = cookie;
|
||||
|
||||
if (!info || !info->opts)
|
||||
return -EINVAL;
|
||||
if (unicast && info->processed)
|
||||
return -EINVAL;
|
||||
if (!tb[TCA_OPTIONS])
|
||||
return NL_CONT;
|
||||
|
||||
libbpf_nla_parse_nested(tbb, TCA_BPF_MAX, tb[TCA_OPTIONS], NULL);
|
||||
if (!tbb[TCA_BPF_ID])
|
||||
return -EINVAL;
|
||||
|
||||
OPTS_SET(info->opts, prog_id, libbpf_nla_getattr_u32(tbb[TCA_BPF_ID]));
|
||||
OPTS_SET(info->opts, handle, tc->tcm_handle);
|
||||
OPTS_SET(info->opts, priority, TC_H_MAJ(tc->tcm_info) >> 16);
|
||||
|
||||
info->processed = true;
|
||||
return unicast ? NL_NEXT : NL_DONE;
|
||||
}
|
||||
|
||||
static int get_tc_info(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn,
|
||||
void *cookie)
|
||||
{
|
||||
struct tcmsg *tc = NLMSG_DATA(nh);
|
||||
struct nlattr *tb[TCA_MAX + 1];
|
||||
|
||||
libbpf_nla_parse(tb, TCA_MAX,
|
||||
(struct nlattr *)((void *)tc + NLMSG_ALIGN(sizeof(*tc))),
|
||||
NLMSG_PAYLOAD(nh, sizeof(*tc)), NULL);
|
||||
if (!tb[TCA_KIND])
|
||||
return NL_CONT;
|
||||
return __get_tc_info(cookie, tc, tb, nh->nlmsg_flags & NLM_F_ECHO);
|
||||
}
|
||||
|
||||
static int tc_add_fd_and_name(struct libbpf_nla_req *req, int fd)
|
||||
{
|
||||
struct bpf_prog_info info = {};
|
||||
__u32 info_len = sizeof(info);
|
||||
char name[256];
|
||||
int len, ret;
|
||||
|
||||
ret = bpf_obj_get_info_by_fd(fd, &info, &info_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = nlattr_add(req, TCA_BPF_FD, &fd, sizeof(fd));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len = snprintf(name, sizeof(name), "%s:[%u]", info.name, info.id);
|
||||
if (len < 0)
|
||||
req.nlh.nlmsg_seq = seq;
|
||||
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
|
||||
return -errno;
|
||||
if (len >= sizeof(name))
|
||||
return -ENAMETOOLONG;
|
||||
return nlattr_add(req, TCA_BPF_NAME, name, len + 1);
|
||||
|
||||
return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
|
||||
dump_link_nlmsg, cookie);
|
||||
}
|
||||
|
||||
int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||
static int __dump_class_nlmsg(struct nlmsghdr *nlh,
|
||||
libbpf_dump_nlmsg_t dump_class_nlmsg,
|
||||
void *cookie)
|
||||
{
|
||||
__u32 protocol, bpf_flags, handle, priority, parent, prog_id, flags;
|
||||
int ret, ifindex, attach_point, prog_fd;
|
||||
struct bpf_cb_ctx info = {};
|
||||
struct libbpf_nla_req req;
|
||||
struct nlattr *nla;
|
||||
struct nlattr *tb[TCA_MAX + 1], *attr;
|
||||
struct tcmsg *t = NLMSG_DATA(nlh);
|
||||
int len;
|
||||
|
||||
if (!hook || !opts ||
|
||||
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||
!OPTS_VALID(opts, bpf_tc_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
|
||||
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
|
||||
if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
|
||||
return -LIBBPF_ERRNO__NLPARSE;
|
||||
|
||||
ifindex = OPTS_GET(hook, ifindex, 0);
|
||||
parent = OPTS_GET(hook, parent, 0);
|
||||
attach_point = OPTS_GET(hook, attach_point, 0);
|
||||
|
||||
handle = OPTS_GET(opts, handle, 0);
|
||||
priority = OPTS_GET(opts, priority, 0);
|
||||
prog_fd = OPTS_GET(opts, prog_fd, 0);
|
||||
prog_id = OPTS_GET(opts, prog_id, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
if (ifindex <= 0 || !prog_fd || prog_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (priority > UINT16_MAX)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (flags & ~BPF_TC_F_REPLACE)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
flags = (flags & BPF_TC_F_REPLACE) ? NLM_F_REPLACE : NLM_F_EXCL;
|
||||
protocol = ETH_P_ALL;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE |
|
||||
NLM_F_ECHO | flags;
|
||||
req.nh.nlmsg_type = RTM_NEWTFILTER;
|
||||
req.tc.tcm_family = AF_UNSPEC;
|
||||
req.tc.tcm_ifindex = ifindex;
|
||||
req.tc.tcm_handle = handle;
|
||||
req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
|
||||
|
||||
ret = tc_get_tcm_parent(attach_point, &parent);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
req.tc.tcm_parent = parent;
|
||||
|
||||
ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
nla = nlattr_begin_nested(&req, TCA_OPTIONS);
|
||||
if (!nla)
|
||||
return libbpf_err(-EMSGSIZE);
|
||||
ret = tc_add_fd_and_name(&req, prog_fd);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
bpf_flags = TCA_BPF_FLAG_ACT_DIRECT;
|
||||
ret = nlattr_add(&req, TCA_BPF_FLAGS, &bpf_flags, sizeof(bpf_flags));
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
nlattr_end_nested(&req, nla);
|
||||
|
||||
info.opts = opts;
|
||||
|
||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
if (!info.processed)
|
||||
return libbpf_err(-ENOENT);
|
||||
return ret;
|
||||
return dump_class_nlmsg(cookie, t, tb);
|
||||
}
|
||||
|
||||
static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||
const struct bpf_tc_opts *opts,
|
||||
const bool flush)
|
||||
int libbpf_nl_get_class(int sock, unsigned int nl_pid, int ifindex,
|
||||
libbpf_dump_nlmsg_t dump_class_nlmsg, void *cookie)
|
||||
{
|
||||
__u32 protocol = 0, handle, priority, parent, prog_id, flags;
|
||||
int ret, ifindex, attach_point, prog_fd;
|
||||
struct libbpf_nla_req req;
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct tcmsg t;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETTCLASS,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.t.tcm_family = AF_UNSPEC,
|
||||
.t.tcm_ifindex = ifindex,
|
||||
};
|
||||
int seq = time(NULL);
|
||||
|
||||
if (!hook ||
|
||||
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||
!OPTS_VALID(opts, bpf_tc_opts))
|
||||
return -EINVAL;
|
||||
req.nlh.nlmsg_seq = seq;
|
||||
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
ifindex = OPTS_GET(hook, ifindex, 0);
|
||||
parent = OPTS_GET(hook, parent, 0);
|
||||
attach_point = OPTS_GET(hook, attach_point, 0);
|
||||
|
||||
handle = OPTS_GET(opts, handle, 0);
|
||||
priority = OPTS_GET(opts, priority, 0);
|
||||
prog_fd = OPTS_GET(opts, prog_fd, 0);
|
||||
prog_id = OPTS_GET(opts, prog_id, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
if (ifindex <= 0 || flags || prog_fd || prog_id)
|
||||
return -EINVAL;
|
||||
if (priority > UINT16_MAX)
|
||||
return -EINVAL;
|
||||
if (!flush) {
|
||||
if (!handle || !priority)
|
||||
return -EINVAL;
|
||||
protocol = ETH_P_ALL;
|
||||
} else {
|
||||
if (handle || priority)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.nh.nlmsg_type = RTM_DELTFILTER;
|
||||
req.tc.tcm_family = AF_UNSPEC;
|
||||
req.tc.tcm_ifindex = ifindex;
|
||||
if (!flush) {
|
||||
req.tc.tcm_handle = handle;
|
||||
req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
|
||||
}
|
||||
|
||||
ret = tc_get_tcm_parent(attach_point, &parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
req.tc.tcm_parent = parent;
|
||||
|
||||
if (!flush) {
|
||||
ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||
return bpf_netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
|
||||
dump_class_nlmsg, cookie);
|
||||
}
|
||||
|
||||
int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||
const struct bpf_tc_opts *opts)
|
||||
static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
|
||||
libbpf_dump_nlmsg_t dump_qdisc_nlmsg,
|
||||
void *cookie)
|
||||
{
|
||||
int ret;
|
||||
struct nlattr *tb[TCA_MAX + 1], *attr;
|
||||
struct tcmsg *t = NLMSG_DATA(nlh);
|
||||
int len;
|
||||
|
||||
if (!opts)
|
||||
return libbpf_err(-EINVAL);
|
||||
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
|
||||
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
|
||||
if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
|
||||
return -LIBBPF_ERRNO__NLPARSE;
|
||||
|
||||
ret = __bpf_tc_detach(hook, opts, false);
|
||||
return libbpf_err(ret);
|
||||
return dump_qdisc_nlmsg(cookie, t, tb);
|
||||
}
|
||||
|
||||
int bpf_tc_query(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||
int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
||||
libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
|
||||
{
|
||||
__u32 protocol, handle, priority, parent, prog_id, flags;
|
||||
int ret, ifindex, attach_point, prog_fd;
|
||||
struct bpf_cb_ctx info = {};
|
||||
struct libbpf_nla_req req;
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct tcmsg t;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETQDISC,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.t.tcm_family = AF_UNSPEC,
|
||||
.t.tcm_ifindex = ifindex,
|
||||
};
|
||||
int seq = time(NULL);
|
||||
|
||||
if (!hook || !opts ||
|
||||
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||
!OPTS_VALID(opts, bpf_tc_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
req.nlh.nlmsg_seq = seq;
|
||||
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
ifindex = OPTS_GET(hook, ifindex, 0);
|
||||
parent = OPTS_GET(hook, parent, 0);
|
||||
attach_point = OPTS_GET(hook, attach_point, 0);
|
||||
|
||||
handle = OPTS_GET(opts, handle, 0);
|
||||
priority = OPTS_GET(opts, priority, 0);
|
||||
prog_fd = OPTS_GET(opts, prog_fd, 0);
|
||||
prog_id = OPTS_GET(opts, prog_id, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
|
||||
if (ifindex <= 0 || flags || prog_fd || prog_id ||
|
||||
!handle || !priority)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (priority > UINT16_MAX)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
protocol = ETH_P_ALL;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST;
|
||||
req.nh.nlmsg_type = RTM_GETTFILTER;
|
||||
req.tc.tcm_family = AF_UNSPEC;
|
||||
req.tc.tcm_ifindex = ifindex;
|
||||
req.tc.tcm_handle = handle;
|
||||
req.tc.tcm_info = TC_H_MAKE(priority << 16, htons(protocol));
|
||||
|
||||
ret = tc_get_tcm_parent(attach_point, &parent);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
req.tc.tcm_parent = parent;
|
||||
|
||||
ret = nlattr_add(&req, TCA_KIND, "bpf", sizeof("bpf"));
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
|
||||
info.opts = opts;
|
||||
|
||||
ret = libbpf_netlink_send_recv(&req, get_tc_info, NULL, &info);
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
if (!info.processed)
|
||||
return libbpf_err(-ENOENT);
|
||||
return ret;
|
||||
return bpf_netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
|
||||
dump_qdisc_nlmsg, cookie);
|
||||
}
|
||||
|
||||
static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
|
||||
libbpf_dump_nlmsg_t dump_filter_nlmsg,
|
||||
void *cookie)
|
||||
{
|
||||
struct nlattr *tb[TCA_MAX + 1], *attr;
|
||||
struct tcmsg *t = NLMSG_DATA(nlh);
|
||||
int len;
|
||||
|
||||
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
|
||||
attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
|
||||
if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
|
||||
return -LIBBPF_ERRNO__NLPARSE;
|
||||
|
||||
return dump_filter_nlmsg(cookie, t, tb);
|
||||
}
|
||||
|
||||
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
||||
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct tcmsg t;
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
|
||||
.nlh.nlmsg_type = RTM_GETTFILTER,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.t.tcm_family = AF_UNSPEC,
|
||||
.t.tcm_ifindex = ifindex,
|
||||
.t.tcm_parent = handle,
|
||||
};
|
||||
int seq = time(NULL);
|
||||
|
||||
req.nlh.nlmsg_seq = seq;
|
||||
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
return bpf_netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
|
||||
dump_filter_nlmsg, cookie);
|
||||
}
|
||||
|
||||
11
src/nlattr.c
11
src/nlattr.c
@@ -7,11 +7,14 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "nlattr.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
|
||||
[LIBBPF_NLA_U8] = sizeof(uint8_t),
|
||||
@@ -27,7 +30,7 @@ static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
|
||||
int totlen = NLA_ALIGN(nla->nla_len);
|
||||
|
||||
*remaining -= totlen;
|
||||
return (struct nlattr *)((void *)nla + totlen);
|
||||
return (struct nlattr *) ((char *) nla + totlen);
|
||||
}
|
||||
|
||||
static int nla_ok(const struct nlattr *nla, int remaining)
|
||||
|
||||
60
src/nlattr.h
60
src/nlattr.h
@@ -10,11 +10,7 @@
|
||||
#define __LIBBPF_NLATTR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
/* avoid multiple definition of netlink features */
|
||||
#define __LINUX_NETLINK_H
|
||||
|
||||
@@ -53,15 +49,6 @@ struct libbpf_nla_policy {
|
||||
uint16_t maxlen;
|
||||
};
|
||||
|
||||
struct libbpf_nla_req {
|
||||
struct nlmsghdr nh;
|
||||
union {
|
||||
struct ifinfomsg ifinfo;
|
||||
struct tcmsg tc;
|
||||
};
|
||||
char buf[128];
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup attr
|
||||
* Iterate over a stream of attributes
|
||||
@@ -81,7 +68,7 @@ struct libbpf_nla_req {
|
||||
*/
|
||||
static inline void *libbpf_nla_data(const struct nlattr *nla)
|
||||
{
|
||||
return (void *)nla + NLA_HDRLEN;
|
||||
return (char *) nla + NLA_HDRLEN;
|
||||
}
|
||||
|
||||
static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
|
||||
@@ -116,49 +103,4 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
|
||||
|
||||
int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
|
||||
|
||||
static inline struct nlattr *nla_data(struct nlattr *nla)
|
||||
{
|
||||
return (struct nlattr *)((void *)nla + NLA_HDRLEN);
|
||||
}
|
||||
|
||||
static inline struct nlattr *req_tail(struct libbpf_nla_req *req)
|
||||
{
|
||||
return (struct nlattr *)((void *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
|
||||
}
|
||||
|
||||
static inline int nlattr_add(struct libbpf_nla_req *req, int type,
|
||||
const void *data, int len)
|
||||
{
|
||||
struct nlattr *nla;
|
||||
|
||||
if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
|
||||
return -EMSGSIZE;
|
||||
if (!!data != !!len)
|
||||
return -EINVAL;
|
||||
|
||||
nla = req_tail(req);
|
||||
nla->nla_type = type;
|
||||
nla->nla_len = NLA_HDRLEN + len;
|
||||
if (data)
|
||||
memcpy(nla_data(nla), data, len);
|
||||
req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
|
||||
{
|
||||
struct nlattr *tail;
|
||||
|
||||
tail = req_tail(req);
|
||||
if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
|
||||
return NULL;
|
||||
return tail;
|
||||
}
|
||||
|
||||
static inline void nlattr_end_nested(struct libbpf_nla_req *req,
|
||||
struct nlattr *tail)
|
||||
{
|
||||
tail->nla_len = (void *)req_tail(req) - (void *)tail;
|
||||
}
|
||||
|
||||
#endif /* __LIBBPF_NLATTR_H */
|
||||
|
||||
1307
src/relo_core.c
1307
src/relo_core.c
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2019 Facebook */
|
||||
|
||||
#ifndef __RELO_CORE_H
|
||||
#define __RELO_CORE_H
|
||||
|
||||
#include <linux/bpf.h>
|
||||
|
||||
struct bpf_core_cand {
|
||||
const struct btf *btf;
|
||||
__u32 id;
|
||||
};
|
||||
|
||||
/* dynamically sized list of type IDs and its associated struct btf */
|
||||
struct bpf_core_cand_list {
|
||||
struct bpf_core_cand *cands;
|
||||
int len;
|
||||
};
|
||||
|
||||
#define BPF_CORE_SPEC_MAX_LEN 64
|
||||
|
||||
/* represents BPF CO-RE field or array element accessor */
|
||||
struct bpf_core_accessor {
|
||||
__u32 type_id; /* struct/union type or array element type */
|
||||
__u32 idx; /* field index or array index */
|
||||
const char *name; /* field name or NULL for array accessor */
|
||||
};
|
||||
|
||||
struct bpf_core_spec {
|
||||
const struct btf *btf;
|
||||
/* high-level spec: named fields and array indices only */
|
||||
struct bpf_core_accessor spec[BPF_CORE_SPEC_MAX_LEN];
|
||||
/* original unresolved (no skip_mods_or_typedefs) root type ID */
|
||||
__u32 root_type_id;
|
||||
/* CO-RE relocation kind */
|
||||
enum bpf_core_relo_kind relo_kind;
|
||||
/* high-level spec length */
|
||||
int len;
|
||||
/* raw, low-level spec: 1-to-1 with accessor spec string */
|
||||
int raw_spec[BPF_CORE_SPEC_MAX_LEN];
|
||||
/* raw spec length */
|
||||
int raw_len;
|
||||
/* field bit offset represented by spec */
|
||||
__u32 bit_offset;
|
||||
};
|
||||
|
||||
struct bpf_core_relo_res {
|
||||
/* expected value in the instruction, unless validate == false */
|
||||
__u32 orig_val;
|
||||
/* new value that needs to be patched up to */
|
||||
__u32 new_val;
|
||||
/* relocation unsuccessful, poison instruction, but don't fail load */
|
||||
bool poison;
|
||||
/* some relocations can't be validated against orig_val */
|
||||
bool validate;
|
||||
/* for field byte offset relocations or the forms:
|
||||
* *(T *)(rX + <off>) = rY
|
||||
* rX = *(T *)(rY + <off>),
|
||||
* we remember original and resolved field size to adjust direct
|
||||
* memory loads of pointers and integers; this is necessary for 32-bit
|
||||
* host kernel architectures, but also allows to automatically
|
||||
* relocate fields that were resized from, e.g., u32 to u64, etc.
|
||||
*/
|
||||
bool fail_memsz_adjust;
|
||||
__u32 orig_sz;
|
||||
__u32 orig_type_id;
|
||||
__u32 new_sz;
|
||||
__u32 new_type_id;
|
||||
};
|
||||
|
||||
int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
|
||||
const struct btf *targ_btf, __u32 targ_id);
|
||||
|
||||
size_t bpf_core_essential_name_len(const char *name);
|
||||
|
||||
int bpf_core_calc_relo_insn(const char *prog_name,
|
||||
const struct bpf_core_relo *relo, int relo_idx,
|
||||
const struct btf *local_btf,
|
||||
struct bpf_core_cand_list *cands,
|
||||
struct bpf_core_spec *specs_scratch,
|
||||
struct bpf_core_relo_res *targ_res);
|
||||
|
||||
int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
|
||||
int insn_idx, const struct bpf_core_relo *relo,
|
||||
int relo_idx, const struct bpf_core_relo_res *res);
|
||||
|
||||
int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
|
||||
const struct bpf_core_relo *relo,
|
||||
struct bpf_core_spec *spec);
|
||||
|
||||
int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *spec);
|
||||
|
||||
#endif
|
||||
@@ -16,11 +16,15 @@
|
||||
#include <asm/barrier.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <tools/libc_compat.h>
|
||||
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "bpf.h"
|
||||
|
||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||
|
||||
struct ring {
|
||||
ring_buffer_sample_fn sample_cb;
|
||||
void *ctx;
|
||||
@@ -69,23 +73,23 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return libbpf_err(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (info.type != BPF_MAP_TYPE_RINGBUF) {
|
||||
pr_warn("ringbuf: map fd=%d is not BPF_MAP_TYPE_RINGBUF\n",
|
||||
map_fd);
|
||||
return libbpf_err(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp = libbpf_reallocarray(rb->rings, rb->ring_cnt + 1, sizeof(*rb->rings));
|
||||
tmp = reallocarray(rb->rings, rb->ring_cnt + 1, sizeof(*rb->rings));
|
||||
if (!tmp)
|
||||
return libbpf_err(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
rb->rings = tmp;
|
||||
|
||||
tmp = libbpf_reallocarray(rb->events, rb->ring_cnt + 1, sizeof(*rb->events));
|
||||
tmp = reallocarray(rb->events, rb->ring_cnt + 1, sizeof(*rb->events));
|
||||
if (!tmp)
|
||||
return libbpf_err(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
rb->events = tmp;
|
||||
|
||||
r = &rb->rings[rb->ring_cnt];
|
||||
@@ -103,7 +107,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
err = -errno;
|
||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return libbpf_err(err);
|
||||
return err;
|
||||
}
|
||||
r->consumer_pos = tmp;
|
||||
|
||||
@@ -118,7 +122,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
ringbuf_unmap_ring(rb, r);
|
||||
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return libbpf_err(err);
|
||||
return err;
|
||||
}
|
||||
r->producer_pos = tmp;
|
||||
r->data = tmp + rb->page_size;
|
||||
@@ -133,7 +137,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
||||
ringbuf_unmap_ring(rb, r);
|
||||
pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n",
|
||||
map_fd, err);
|
||||
return libbpf_err(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
rb->ring_cnt++;
|
||||
@@ -165,11 +169,11 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,
|
||||
int err;
|
||||
|
||||
if (!OPTS_VALID(opts, ring_buffer_opts))
|
||||
return errno = EINVAL, NULL;
|
||||
return NULL;
|
||||
|
||||
rb = calloc(1, sizeof(*rb));
|
||||
if (!rb)
|
||||
return errno = ENOMEM, NULL;
|
||||
return NULL;
|
||||
|
||||
rb->page_size = getpagesize();
|
||||
|
||||
@@ -188,7 +192,7 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,
|
||||
|
||||
err_out:
|
||||
ring_buffer__free(rb);
|
||||
return errno = -err, NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int roundup_len(__u32 len)
|
||||
@@ -202,11 +206,9 @@ static inline int roundup_len(__u32 len)
|
||||
return (len + 7) / 8 * 8;
|
||||
}
|
||||
|
||||
static int64_t ringbuf_process_ring(struct ring* r)
|
||||
static int ringbuf_process_ring(struct ring* r)
|
||||
{
|
||||
int *len_ptr, len, err;
|
||||
/* 64-bit to avoid overflow in case of extreme application behavior */
|
||||
int64_t cnt = 0;
|
||||
int *len_ptr, len, err, cnt = 0;
|
||||
unsigned long cons_pos, prod_pos;
|
||||
bool got_new_data;
|
||||
void *sample;
|
||||
@@ -229,7 +231,7 @@ static int64_t ringbuf_process_ring(struct ring* r)
|
||||
if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) {
|
||||
sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ;
|
||||
err = r->sample_cb(r->ctx, sample, len);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
/* update consumer pos and bail out */
|
||||
smp_store_release(r->consumer_pos,
|
||||
cons_pos);
|
||||
@@ -246,57 +248,41 @@ done:
|
||||
}
|
||||
|
||||
/* Consume available ring buffer(s) data without event polling.
|
||||
* Returns number of records consumed across all registered ring buffers (or
|
||||
* INT_MAX, whichever is less), or negative number if any of the callbacks
|
||||
* return error.
|
||||
* Returns number of records consumed across all registered ring buffers, or
|
||||
* negative number if any of the callbacks return error.
|
||||
*/
|
||||
int ring_buffer__consume(struct ring_buffer *rb)
|
||||
{
|
||||
int64_t err, res = 0;
|
||||
int i;
|
||||
int i, err, res = 0;
|
||||
|
||||
for (i = 0; i < rb->ring_cnt; i++) {
|
||||
struct ring *ring = &rb->rings[i];
|
||||
|
||||
err = ringbuf_process_ring(ring);
|
||||
if (err < 0)
|
||||
return libbpf_err(err);
|
||||
return err;
|
||||
res += err;
|
||||
}
|
||||
if (res > INT_MAX)
|
||||
return INT_MAX;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Poll for available data and consume records, if any are available.
|
||||
* Returns number of records consumed (or INT_MAX, whichever is less), or
|
||||
* negative number, if any of the registered callbacks returned error.
|
||||
* Returns number of records consumed, or negative number, if any of the
|
||||
* registered callbacks returned error.
|
||||
*/
|
||||
int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms)
|
||||
{
|
||||
int i, cnt;
|
||||
int64_t err, res = 0;
|
||||
int i, cnt, err, res = 0;
|
||||
|
||||
cnt = epoll_wait(rb->epoll_fd, rb->events, rb->ring_cnt, timeout_ms);
|
||||
if (cnt < 0)
|
||||
return libbpf_err(-errno);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
__u32 ring_id = rb->events[i].data.fd;
|
||||
struct ring *ring = &rb->rings[ring_id];
|
||||
|
||||
err = ringbuf_process_ring(ring);
|
||||
if (err < 0)
|
||||
return libbpf_err(err);
|
||||
res += err;
|
||||
return err;
|
||||
res += cnt;
|
||||
}
|
||||
if (res > INT_MAX)
|
||||
return INT_MAX;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get an fd that can be used to sleep until data is available in the ring(s) */
|
||||
int ring_buffer__epoll_fd(const struct ring_buffer *rb)
|
||||
{
|
||||
return rb->epoll_fd;
|
||||
return cnt < 0 ? -errno : res;
|
||||
}
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
#ifndef __SKEL_INTERNAL_H
|
||||
#define __SKEL_INTERNAL_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bpf.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdlib.h>
|
||||
#include "bpf.h"
|
||||
#endif
|
||||
|
||||
#ifndef __NR_bpf
|
||||
# if defined(__mips__) && defined(_ABIO32)
|
||||
# define __NR_bpf 4355
|
||||
# elif defined(__mips__) && defined(_ABIN32)
|
||||
# define __NR_bpf 6319
|
||||
# elif defined(__mips__) && defined(_ABI64)
|
||||
# define __NR_bpf 5315
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* This file is a base header for auto-generated *.lskel.h files.
|
||||
* Its contents will change and may become part of auto-generation in the future.
|
||||
*
|
||||
* The layout of bpf_[map|prog]_desc and bpf_loader_ctx is feature dependent
|
||||
* and will change from one version of libbpf to another and features
|
||||
* requested during loader program generation.
|
||||
*/
|
||||
struct bpf_map_desc {
|
||||
/* output of the loader prog */
|
||||
int map_fd;
|
||||
/* input for the loader prog */
|
||||
__u32 max_entries;
|
||||
__aligned_u64 initial_value;
|
||||
};
|
||||
struct bpf_prog_desc {
|
||||
int prog_fd;
|
||||
};
|
||||
|
||||
enum {
|
||||
BPF_SKEL_KERNEL = (1ULL << 0),
|
||||
};
|
||||
|
||||
struct bpf_loader_ctx {
|
||||
__u32 sz;
|
||||
__u32 flags;
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
__u64 log_buf;
|
||||
};
|
||||
|
||||
struct bpf_load_and_run_opts {
|
||||
struct bpf_loader_ctx *ctx;
|
||||
const void *data;
|
||||
const void *insns;
|
||||
__u32 data_sz;
|
||||
__u32 insns_sz;
|
||||
const char *errstr;
|
||||
};
|
||||
|
||||
long bpf_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
|
||||
|
||||
static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
|
||||
unsigned int size)
|
||||
{
|
||||
#ifdef __KERNEL__
|
||||
return bpf_sys_bpf(cmd, attr, size);
|
||||
#else
|
||||
return syscall(__NR_bpf, cmd, attr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
static inline int close(int fd)
|
||||
{
|
||||
return close_fd(fd);
|
||||
}
|
||||
|
||||
static inline void *skel_alloc(size_t size)
|
||||
{
|
||||
struct bpf_loader_ctx *ctx = kzalloc(size, GFP_KERNEL);
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
ctx->flags |= BPF_SKEL_KERNEL;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static inline void skel_free(const void *p)
|
||||
{
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
/* skel->bss/rodata maps are populated the following way:
|
||||
*
|
||||
* For kernel use:
|
||||
* skel_prep_map_data() allocates kernel memory that kernel module can directly access.
|
||||
* Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
|
||||
* 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 nessary.
|
||||
*
|
||||
* For user space:
|
||||
* skel_prep_map_data() mmaps anon memory into skel->rodata that can be accessed directly.
|
||||
* Generated lskel stores the pointer in skel->rodata and in skel->maps.rodata.initial_value.
|
||||
* The loader program will perform copy_from_user() from maps.rodata.initial_value.
|
||||
* skel_finalize_map_data() remaps bpf array map value from the kernel memory into
|
||||
* skel->rodata address.
|
||||
*
|
||||
* The "bpftool gen skeleton -L" command generates lskel.h that is suitable for
|
||||
* both kernel and user space. The generated loader program does
|
||||
* either bpf_probe_read_kernel() or bpf_copy_from_user() from initial_value
|
||||
* depending on bpf_loader_ctx->flags.
|
||||
*/
|
||||
static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
|
||||
{
|
||||
if (addr != ~0ULL)
|
||||
kvfree(p);
|
||||
/* When addr == ~0ULL the 'p' points to
|
||||
* ((struct bpf_array *)map)->value. See skel_finalize_map_data.
|
||||
*/
|
||||
}
|
||||
|
||||
static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = kvmalloc(val_sz, GFP_KERNEL);
|
||||
if (!addr)
|
||||
return NULL;
|
||||
memcpy(addr, val, val_sz);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
|
||||
{
|
||||
struct bpf_map *map;
|
||||
void *addr = NULL;
|
||||
|
||||
kvfree((void *) (long) *init_val);
|
||||
*init_val = ~0ULL;
|
||||
|
||||
/* At this point bpf_load_and_run() finished without error and
|
||||
* 'fd' is a valid bpf map FD. All sanity checks below should succeed.
|
||||
*/
|
||||
map = bpf_map_get(fd);
|
||||
if (IS_ERR(map))
|
||||
return NULL;
|
||||
if (map->map_type != BPF_MAP_TYPE_ARRAY)
|
||||
goto out;
|
||||
addr = ((struct bpf_array *)map)->value;
|
||||
/* the addr stays valid, since FD is not closed */
|
||||
out:
|
||||
bpf_map_put(map);
|
||||
return addr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void *skel_alloc(size_t size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
static inline void skel_free(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
|
||||
{
|
||||
munmap(p, sz);
|
||||
}
|
||||
|
||||
static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == (void *) -1)
|
||||
return NULL;
|
||||
memcpy(addr, val, val_sz);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0);
|
||||
if (addr == (void *) -1)
|
||||
return NULL;
|
||||
return addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int skel_closenz(int fd)
|
||||
{
|
||||
if (fd > 0)
|
||||
return close(fd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifndef offsetofend
|
||||
#define offsetofend(TYPE, MEMBER) \
|
||||
(offsetof(TYPE, MEMBER) + sizeof((((TYPE *)0)->MEMBER)))
|
||||
#endif
|
||||
|
||||
static inline int skel_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
__u32 key_size,
|
||||
__u32 value_size,
|
||||
__u32 max_entries)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
|
||||
attr.map_type = map_type;
|
||||
strncpy(attr.map_name, map_name, sizeof(attr.map_name));
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.max_entries = max_entries;
|
||||
|
||||
return skel_sys_bpf(BPF_MAP_CREATE, &attr, attr_sz);
|
||||
}
|
||||
|
||||
static inline int skel_map_update_elem(int fd, const void *key,
|
||||
const void *value, __u64 flags)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, flags);
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.map_fd = fd;
|
||||
attr.key = (long) key;
|
||||
attr.value = (long) value;
|
||||
attr.flags = flags;
|
||||
|
||||
return skel_sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, attr_sz);
|
||||
}
|
||||
|
||||
static inline int skel_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, raw_tracepoint.prog_fd);
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.raw_tracepoint.name = (long) name;
|
||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||
|
||||
return skel_sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, attr_sz);
|
||||
}
|
||||
|
||||
static inline int skel_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, link_create.iter_info_len);
|
||||
union bpf_attr attr;
|
||||
|
||||
memset(&attr, 0, attr_sz);
|
||||
attr.link_create.prog_fd = prog_fd;
|
||||
attr.link_create.target_fd = target_fd;
|
||||
attr.link_create.attach_type = attach_type;
|
||||
|
||||
return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define set_err
|
||||
#else
|
||||
#define set_err err = -errno
|
||||
#endif
|
||||
|
||||
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
|
||||
{
|
||||
int map_fd = -1, prog_fd = -1, key = 0, err;
|
||||
union bpf_attr attr;
|
||||
|
||||
err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1);
|
||||
if (map_fd < 0) {
|
||||
opts->errstr = "failed to create loader map";
|
||||
set_err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = skel_map_update_elem(map_fd, &key, opts->data, 0);
|
||||
if (err < 0) {
|
||||
opts->errstr = "failed to update loader map";
|
||||
set_err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
|
||||
attr.insns = (long) opts->insns;
|
||||
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
|
||||
attr.license = (long) "Dual BSD/GPL";
|
||||
memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
|
||||
attr.fd_array = (long) &map_fd;
|
||||
attr.log_level = opts->ctx->log_level;
|
||||
attr.log_size = opts->ctx->log_size;
|
||||
attr.log_buf = opts->ctx->log_buf;
|
||||
attr.prog_flags = BPF_F_SLEEPABLE;
|
||||
err = prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
if (prog_fd < 0) {
|
||||
opts->errstr = "failed to load loader prog";
|
||||
set_err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.test.prog_fd = prog_fd;
|
||||
attr.test.ctx_in = (long) opts->ctx;
|
||||
attr.test.ctx_size_in = opts->ctx->sz;
|
||||
err = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));
|
||||
if (err < 0 || (int)attr.test.retval < 0) {
|
||||
opts->errstr = "failed to execute loader prog";
|
||||
if (err < 0) {
|
||||
set_err;
|
||||
} else {
|
||||
err = (int)attr.test.retval;
|
||||
#ifndef __KERNEL__
|
||||
errno = -err;
|
||||
#endif
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
err = 0;
|
||||
out:
|
||||
if (map_fd >= 0)
|
||||
close(map_fd);
|
||||
if (prog_fd >= 0)
|
||||
close(prog_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
177
src/strset.c
177
src/strset.c
@@ -1,177 +0,0 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
#include "hashmap.h"
|
||||
#include "libbpf_internal.h"
|
||||
#include "strset.h"
|
||||
|
||||
struct strset {
|
||||
void *strs_data;
|
||||
size_t strs_data_len;
|
||||
size_t strs_data_cap;
|
||||
size_t strs_data_max_len;
|
||||
|
||||
/* lookup index for each unique string in strings set */
|
||||
struct hashmap *strs_hash;
|
||||
};
|
||||
|
||||
static size_t strset_hash_fn(const void *key, void *ctx)
|
||||
{
|
||||
const struct strset *s = ctx;
|
||||
const char *str = s->strs_data + (long)key;
|
||||
|
||||
return str_hash(str);
|
||||
}
|
||||
|
||||
static bool strset_equal_fn(const void *key1, const void *key2, void *ctx)
|
||||
{
|
||||
const struct strset *s = ctx;
|
||||
const char *str1 = s->strs_data + (long)key1;
|
||||
const char *str2 = s->strs_data + (long)key2;
|
||||
|
||||
return strcmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
struct strset *strset__new(size_t max_data_sz, const char *init_data, size_t init_data_sz)
|
||||
{
|
||||
struct strset *set = calloc(1, sizeof(*set));
|
||||
struct hashmap *hash;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (!set)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hash = hashmap__new(strset_hash_fn, strset_equal_fn, set);
|
||||
if (IS_ERR(hash))
|
||||
goto err_out;
|
||||
|
||||
set->strs_data_max_len = max_data_sz;
|
||||
set->strs_hash = hash;
|
||||
|
||||
if (init_data) {
|
||||
long off;
|
||||
|
||||
set->strs_data = malloc(init_data_sz);
|
||||
if (!set->strs_data)
|
||||
goto err_out;
|
||||
|
||||
memcpy(set->strs_data, init_data, init_data_sz);
|
||||
set->strs_data_len = init_data_sz;
|
||||
set->strs_data_cap = init_data_sz;
|
||||
|
||||
for (off = 0; off < set->strs_data_len; off += strlen(set->strs_data + off) + 1) {
|
||||
/* hashmap__add() returns EEXIST if string with the same
|
||||
* content already is in the hash map
|
||||
*/
|
||||
err = hashmap__add(hash, (void *)off, (void *)off);
|
||||
if (err == -EEXIST)
|
||||
continue; /* duplicate */
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
err_out:
|
||||
strset__free(set);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void strset__free(struct strset *set)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(set))
|
||||
return;
|
||||
|
||||
hashmap__free(set->strs_hash);
|
||||
free(set->strs_data);
|
||||
free(set);
|
||||
}
|
||||
|
||||
size_t strset__data_size(const struct strset *set)
|
||||
{
|
||||
return set->strs_data_len;
|
||||
}
|
||||
|
||||
const char *strset__data(const struct strset *set)
|
||||
{
|
||||
return set->strs_data;
|
||||
}
|
||||
|
||||
static void *strset_add_str_mem(struct strset *set, size_t add_sz)
|
||||
{
|
||||
return libbpf_add_mem(&set->strs_data, &set->strs_data_cap, 1,
|
||||
set->strs_data_len, set->strs_data_max_len, add_sz);
|
||||
}
|
||||
|
||||
/* Find string offset that corresponds to a given string *s*.
|
||||
* Returns:
|
||||
* - >0 offset into string data, if string is found;
|
||||
* - -ENOENT, if string is not in the string data;
|
||||
* - <0, on any other error.
|
||||
*/
|
||||
int strset__find_str(struct strset *set, const char *s)
|
||||
{
|
||||
long old_off, new_off, len;
|
||||
void *p;
|
||||
|
||||
/* see strset__add_str() for why we do this */
|
||||
len = strlen(s) + 1;
|
||||
p = strset_add_str_mem(set, len);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
new_off = set->strs_data_len;
|
||||
memcpy(p, s, len);
|
||||
|
||||
if (hashmap__find(set->strs_hash, (void *)new_off, (void **)&old_off))
|
||||
return old_off;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Add a string s to the string data. If the string already exists, return its
|
||||
* offset within string data.
|
||||
* Returns:
|
||||
* - > 0 offset into string data, on success;
|
||||
* - < 0, on error.
|
||||
*/
|
||||
int strset__add_str(struct strset *set, const char *s)
|
||||
{
|
||||
long old_off, new_off, len;
|
||||
void *p;
|
||||
int err;
|
||||
|
||||
/* Hashmap keys are always offsets within set->strs_data, so to even
|
||||
* look up some string from the "outside", we need to first append it
|
||||
* at the end, so that it can be addressed with an offset. Luckily,
|
||||
* until set->strs_data_len is incremented, that string is just a piece
|
||||
* of garbage for the rest of the code, so no harm, no foul. On the
|
||||
* other hand, if the string is unique, it's already appended and
|
||||
* ready to be used, only a simple set->strs_data_len increment away.
|
||||
*/
|
||||
len = strlen(s) + 1;
|
||||
p = strset_add_str_mem(set, len);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
new_off = set->strs_data_len;
|
||||
memcpy(p, s, len);
|
||||
|
||||
/* Now attempt to add the string, but only if the string with the same
|
||||
* contents doesn't exist already (HASHMAP_ADD strategy). If such
|
||||
* string exists, we'll get its offset in old_off (that's old_key).
|
||||
*/
|
||||
err = hashmap__insert(set->strs_hash, (void *)new_off, (void *)new_off,
|
||||
HASHMAP_ADD, (const void **)&old_off, NULL);
|
||||
if (err == -EEXIST)
|
||||
return old_off; /* duplicated string, return existing offset */
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set->strs_data_len += len; /* new unique string, adjust data length */
|
||||
return new_off;
|
||||
}
|
||||
21
src/strset.h
21
src/strset.h
@@ -1,21 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
|
||||
/* Copyright (c) 2021 Facebook */
|
||||
#ifndef __LIBBPF_STRSET_H
|
||||
#define __LIBBPF_STRSET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct strset;
|
||||
|
||||
struct strset *strset__new(size_t max_data_sz, const char *init_data, size_t init_data_sz);
|
||||
void strset__free(struct strset *set);
|
||||
|
||||
const char *strset__data(const struct strset *set);
|
||||
size_t strset__data_size(const struct strset *set);
|
||||
|
||||
int strset__find_str(struct strset *set, const char *s);
|
||||
int strset__add_str(struct strset *set, const char *s);
|
||||
|
||||
#endif /* __LIBBPF_STRSET_H */
|
||||
259
src/usdt.bpf.h
259
src/usdt.bpf.h
@@ -1,259 +0,0 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||
#ifndef __USDT_BPF_H__
|
||||
#define __USDT_BPF_H__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
|
||||
/* Below types and maps are internal implementation details of libbpf's USDT
|
||||
* support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
|
||||
* be considered an unstable API as well and might be adjusted based on user
|
||||
* feedback from using libbpf's USDT support in production.
|
||||
*/
|
||||
|
||||
/* User can override BPF_USDT_MAX_SPEC_CNT to change default size of internal
|
||||
* map that keeps track of USDT argument specifications. This might be
|
||||
* necessary if there are a lot of USDT attachments.
|
||||
*/
|
||||
#ifndef BPF_USDT_MAX_SPEC_CNT
|
||||
#define BPF_USDT_MAX_SPEC_CNT 256
|
||||
#endif
|
||||
/* User can override BPF_USDT_MAX_IP_CNT to change default size of internal
|
||||
* map that keeps track of IP (memory address) mapping to USDT argument
|
||||
* specification.
|
||||
* Note, if kernel supports BPF cookies, this map is not used and could be
|
||||
* resized all the way to 1 to save a bit of memory.
|
||||
*/
|
||||
#ifndef BPF_USDT_MAX_IP_CNT
|
||||
#define BPF_USDT_MAX_IP_CNT (4 * BPF_USDT_MAX_SPEC_CNT)
|
||||
#endif
|
||||
/* We use BPF CO-RE to detect support for BPF cookie from BPF side. This is
|
||||
* the only dependency on CO-RE, so if it's undesirable, user can override
|
||||
* BPF_USDT_HAS_BPF_COOKIE to specify whether to BPF cookie is supported or not.
|
||||
*/
|
||||
#ifndef BPF_USDT_HAS_BPF_COOKIE
|
||||
#define BPF_USDT_HAS_BPF_COOKIE \
|
||||
bpf_core_enum_value_exists(enum bpf_func_id___usdt, BPF_FUNC_get_attach_cookie___usdt)
|
||||
#endif
|
||||
|
||||
enum __bpf_usdt_arg_type {
|
||||
BPF_USDT_ARG_CONST,
|
||||
BPF_USDT_ARG_REG,
|
||||
BPF_USDT_ARG_REG_DEREF,
|
||||
};
|
||||
|
||||
struct __bpf_usdt_arg_spec {
|
||||
/* u64 scalar interpreted depending on arg_type, see below */
|
||||
__u64 val_off;
|
||||
/* 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;
|
||||
/* whether arg should be interpreted as signed value */
|
||||
bool arg_signed;
|
||||
/* number of bits that need to be cleared and, optionally,
|
||||
* sign-extended to cast arguments that are 1, 2, or 4 bytes
|
||||
* long into final 8-byte u64/s64 value returned to user
|
||||
*/
|
||||
char arg_bitshift;
|
||||
};
|
||||
|
||||
/* should match USDT_MAX_ARG_CNT in usdt.c exactly */
|
||||
#define BPF_USDT_MAX_ARG_CNT 12
|
||||
struct __bpf_usdt_spec {
|
||||
struct __bpf_usdt_arg_spec args[BPF_USDT_MAX_ARG_CNT];
|
||||
__u64 usdt_cookie;
|
||||
short arg_cnt;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, BPF_USDT_MAX_SPEC_CNT);
|
||||
__type(key, int);
|
||||
__type(value, struct __bpf_usdt_spec);
|
||||
} __bpf_usdt_specs SEC(".maps") __weak;
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, BPF_USDT_MAX_IP_CNT);
|
||||
__type(key, long);
|
||||
__type(value, __u32);
|
||||
} __bpf_usdt_ip_to_spec_id SEC(".maps") __weak;
|
||||
|
||||
/* don't rely on user's BPF code to have latest definition of bpf_func_id */
|
||||
enum bpf_func_id___usdt {
|
||||
BPF_FUNC_get_attach_cookie___usdt = 0xBAD, /* value doesn't matter */
|
||||
};
|
||||
|
||||
static __always_inline
|
||||
int __bpf_usdt_spec_id(struct pt_regs *ctx)
|
||||
{
|
||||
if (!BPF_USDT_HAS_BPF_COOKIE) {
|
||||
long ip = PT_REGS_IP(ctx);
|
||||
int *spec_id_ptr;
|
||||
|
||||
spec_id_ptr = bpf_map_lookup_elem(&__bpf_usdt_ip_to_spec_id, &ip);
|
||||
return spec_id_ptr ? *spec_id_ptr : -ESRCH;
|
||||
}
|
||||
|
||||
return bpf_get_attach_cookie(ctx);
|
||||
}
|
||||
|
||||
/* Return number of USDT arguments defined for currently traced USDT. */
|
||||
__weak __hidden
|
||||
int bpf_usdt_arg_cnt(struct pt_regs *ctx)
|
||||
{
|
||||
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;
|
||||
|
||||
return spec->arg_cnt;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
__weak __hidden
|
||||
int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res)
|
||||
{
|
||||
struct __bpf_usdt_spec *spec;
|
||||
struct __bpf_usdt_arg_spec *arg_spec;
|
||||
unsigned long val;
|
||||
int err, spec_id;
|
||||
|
||||
*res = 0;
|
||||
|
||||
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 || arg_num >= spec->arg_cnt)
|
||||
return -ENOENT;
|
||||
|
||||
arg_spec = &spec->args[arg_num];
|
||||
switch (arg_spec->arg_type) {
|
||||
case BPF_USDT_ARG_CONST:
|
||||
/* Arg is just a constant ("-4@$-9" in USDT arg spec).
|
||||
* value is recorded in arg_spec->val_off directly.
|
||||
*/
|
||||
val = arg_spec->val_off;
|
||||
break;
|
||||
case BPF_USDT_ARG_REG:
|
||||
/* Arg is in a register (e.g, "8@%rax" in USDT arg spec),
|
||||
* so we read the contents of that register directly from
|
||||
* struct pt_regs. To keep things simple user-space parts
|
||||
* record offsetof(struct pt_regs, <regname>) in arg_spec->reg_off.
|
||||
*/
|
||||
err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case BPF_USDT_ARG_REG_DEREF:
|
||||
/* Arg is in memory addressed by register, plus some offset
|
||||
* (e.g., "-4@-1204(%rbp)" in USDT arg spec). Register is
|
||||
* identified like with BPF_USDT_ARG_REG case, and the offset
|
||||
* is in arg_spec->val_off. We first fetch register contents
|
||||
* from pt_regs, then do another user-space probe read to
|
||||
* fetch argument value itself.
|
||||
*/
|
||||
err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off);
|
||||
if (err)
|
||||
return err;
|
||||
err = bpf_probe_read_user(&val, sizeof(val), (void *)val + arg_spec->val_off);
|
||||
if (err)
|
||||
return err;
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
val >>= arg_spec->arg_bitshift;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* cast arg from 1, 2, or 4 bytes to final 8 byte size clearing
|
||||
* necessary upper arg_bitshift bits, with sign extension if argument
|
||||
* is signed
|
||||
*/
|
||||
val <<= arg_spec->arg_bitshift;
|
||||
if (arg_spec->arg_signed)
|
||||
val = ((long)val) >> arg_spec->arg_bitshift;
|
||||
else
|
||||
val = val >> arg_spec->arg_bitshift;
|
||||
*res = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve user-specified cookie value provided during attach as
|
||||
* bpf_usdt_opts.usdt_cookie. This serves the same purpose as BPF cookie
|
||||
* returned by bpf_get_attach_cookie(). Libbpf's support for USDT is itself
|
||||
* utilizing BPF cookies internally, so user can't use BPF cookie directly
|
||||
* for USDT programs and has to use bpf_usdt_cookie() API instead.
|
||||
*/
|
||||
__weak __hidden
|
||||
long bpf_usdt_cookie(struct pt_regs *ctx)
|
||||
{
|
||||
struct __bpf_usdt_spec *spec;
|
||||
int spec_id;
|
||||
|
||||
spec_id = __bpf_usdt_spec_id(ctx);
|
||||
if (spec_id < 0)
|
||||
return 0;
|
||||
|
||||
spec = bpf_map_lookup_elem(&__bpf_usdt_specs, &spec_id);
|
||||
if (!spec)
|
||||
return 0;
|
||||
|
||||
return spec->usdt_cookie;
|
||||
}
|
||||
|
||||
/* we rely on ___bpf_apply() and ___bpf_narg() macros already defined in bpf_tracing.h */
|
||||
#define ___bpf_usdt_args0() ctx
|
||||
#define ___bpf_usdt_args1(x) ___bpf_usdt_args0(), ({ long _x; bpf_usdt_arg(ctx, 0, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args2(x, args...) ___bpf_usdt_args1(args), ({ long _x; bpf_usdt_arg(ctx, 1, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args3(x, args...) ___bpf_usdt_args2(args), ({ long _x; bpf_usdt_arg(ctx, 2, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args4(x, args...) ___bpf_usdt_args3(args), ({ long _x; bpf_usdt_arg(ctx, 3, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args5(x, args...) ___bpf_usdt_args4(args), ({ long _x; bpf_usdt_arg(ctx, 4, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args6(x, args...) ___bpf_usdt_args5(args), ({ long _x; bpf_usdt_arg(ctx, 5, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args7(x, args...) ___bpf_usdt_args6(args), ({ long _x; bpf_usdt_arg(ctx, 6, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args8(x, args...) ___bpf_usdt_args7(args), ({ long _x; bpf_usdt_arg(ctx, 7, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args9(x, args...) ___bpf_usdt_args8(args), ({ long _x; bpf_usdt_arg(ctx, 8, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args10(x, args...) ___bpf_usdt_args9(args), ({ long _x; bpf_usdt_arg(ctx, 9, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args11(x, args...) ___bpf_usdt_args10(args), ({ long _x; bpf_usdt_arg(ctx, 10, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args12(x, args...) ___bpf_usdt_args11(args), ({ long _x; bpf_usdt_arg(ctx, 11, &_x); (void *)_x; })
|
||||
#define ___bpf_usdt_args(args...) ___bpf_apply(___bpf_usdt_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_USDT serves the same purpose for USDT handlers as BPF_PROG for
|
||||
* tp_btf/fentry/fexit BPF programs and BPF_KPROBE for kprobes.
|
||||
* Original struct pt_regs * context is preserved as 'ctx' argument.
|
||||
*/
|
||||
#define BPF_USDT(name, args...) \
|
||||
name(struct pt_regs *ctx); \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args); \
|
||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
{ \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
return ____##name(___bpf_usdt_args(args)); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
} \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#endif /* __USDT_BPF_H__ */
|
||||
1518
src/usdt.c
1518
src/usdt.c
File diff suppressed because it is too large
Load Diff
182
src/xsk.h
182
src/xsk.h
@@ -3,8 +3,7 @@
|
||||
/*
|
||||
* AF_XDP user-space access library.
|
||||
*
|
||||
* Copyright (c) 2018 - 2019 Intel Corporation.
|
||||
* Copyright (c) 2019 Facebook
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation.
|
||||
*
|
||||
* Author(s): Magnus Karlsson <magnus.karlsson@intel.com>
|
||||
*/
|
||||
@@ -14,86 +13,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/if_xdp.h>
|
||||
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This whole API has been deprecated and moved to libxdp that can be found at
|
||||
* https://github.com/xdp-project/xdp-tools. The APIs are exactly the same so
|
||||
* it should just be linking with libxdp instead of libbpf for this set of
|
||||
* functionality. If not, please submit a bug report on the aforementioned page.
|
||||
*/
|
||||
|
||||
/* Load-Acquire Store-Release barriers used by the XDP socket
|
||||
* library. The following macros should *NOT* be considered part of
|
||||
* the xsk.h API, and is subject to change anytime.
|
||||
*
|
||||
* LIBRARY INTERNAL
|
||||
*/
|
||||
|
||||
#define __XSK_READ_ONCE(x) (*(volatile typeof(x) *)&x)
|
||||
#define __XSK_WRITE_ONCE(x, v) (*(volatile typeof(x) *)&x) = (v)
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# define libbpf_smp_store_release(p, v) \
|
||||
do { \
|
||||
asm volatile("" : : : "memory"); \
|
||||
__XSK_WRITE_ONCE(*p, v); \
|
||||
} while (0)
|
||||
# define libbpf_smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = __XSK_READ_ONCE(*p); \
|
||||
asm volatile("" : : : "memory"); \
|
||||
___p1; \
|
||||
})
|
||||
#elif defined(__aarch64__)
|
||||
# define libbpf_smp_store_release(p, v) \
|
||||
asm volatile ("stlr %w1, %0" : "=Q" (*p) : "r" (v) : "memory")
|
||||
# define libbpf_smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1; \
|
||||
asm volatile ("ldar %w0, %1" \
|
||||
: "=r" (___p1) : "Q" (*p) : "memory"); \
|
||||
___p1; \
|
||||
})
|
||||
#elif defined(__riscv)
|
||||
# define libbpf_smp_store_release(p, v) \
|
||||
do { \
|
||||
asm volatile ("fence rw,w" : : : "memory"); \
|
||||
__XSK_WRITE_ONCE(*p, v); \
|
||||
} while (0)
|
||||
# define libbpf_smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = __XSK_READ_ONCE(*p); \
|
||||
asm volatile ("fence r,rw" : : : "memory"); \
|
||||
___p1; \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifndef libbpf_smp_store_release
|
||||
#define libbpf_smp_store_release(p, v) \
|
||||
do { \
|
||||
__sync_synchronize(); \
|
||||
__XSK_WRITE_ONCE(*p, v); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef libbpf_smp_load_acquire
|
||||
#define libbpf_smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = __XSK_READ_ONCE(*p); \
|
||||
__sync_synchronize(); \
|
||||
___p1; \
|
||||
})
|
||||
#endif
|
||||
|
||||
/* LIBRARY INTERNAL -- END */
|
||||
|
||||
/* Do not access these members directly. Use the functions below. */
|
||||
#define DEFINE_XSK_RING(name) \
|
||||
struct name { \
|
||||
@@ -168,8 +96,7 @@ static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
||||
* this function. Without this optimization it whould have been
|
||||
* free_entries = r->cached_prod - r->cached_cons + r->size.
|
||||
*/
|
||||
r->cached_cons = libbpf_smp_load_acquire(r->consumer);
|
||||
r->cached_cons += r->size;
|
||||
r->cached_cons = *r->consumer + r->size;
|
||||
|
||||
return r->cached_cons - r->cached_prod;
|
||||
}
|
||||
@@ -179,14 +106,15 @@ static inline __u32 xsk_cons_nb_avail(struct xsk_ring_cons *r, __u32 nb)
|
||||
__u32 entries = r->cached_prod - r->cached_cons;
|
||||
|
||||
if (entries == 0) {
|
||||
r->cached_prod = libbpf_smp_load_acquire(r->producer);
|
||||
r->cached_prod = *r->producer;
|
||||
entries = r->cached_prod - r->cached_cons;
|
||||
}
|
||||
|
||||
return (entries > nb) ? nb : entries;
|
||||
}
|
||||
|
||||
static inline __u32 xsk_ring_prod__reserve(struct xsk_ring_prod *prod, __u32 nb, __u32 *idx)
|
||||
static inline size_t xsk_ring_prod__reserve(struct xsk_ring_prod *prod,
|
||||
size_t nb, __u32 *idx)
|
||||
{
|
||||
if (xsk_prod_nb_free(prod, nb) < nb)
|
||||
return 0;
|
||||
@@ -197,19 +125,27 @@ static inline __u32 xsk_ring_prod__reserve(struct xsk_ring_prod *prod, __u32 nb,
|
||||
return nb;
|
||||
}
|
||||
|
||||
static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, __u32 nb)
|
||||
static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, size_t nb)
|
||||
{
|
||||
/* Make sure everything has been written to the ring before indicating
|
||||
* this to the kernel by writing the producer pointer.
|
||||
*/
|
||||
libbpf_smp_store_release(prod->producer, *prod->producer + nb);
|
||||
libbpf_smp_wmb();
|
||||
|
||||
*prod->producer += nb;
|
||||
}
|
||||
|
||||
static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx)
|
||||
static inline size_t xsk_ring_cons__peek(struct xsk_ring_cons *cons,
|
||||
size_t nb, __u32 *idx)
|
||||
{
|
||||
__u32 entries = xsk_cons_nb_avail(cons, nb);
|
||||
size_t entries = xsk_cons_nb_avail(cons, nb);
|
||||
|
||||
if (entries > 0) {
|
||||
/* Make sure we do not speculatively read the data before
|
||||
* we have received the packet buffers from the ring.
|
||||
*/
|
||||
libbpf_smp_rmb();
|
||||
|
||||
*idx = cons->cached_cons;
|
||||
cons->cached_cons += entries;
|
||||
}
|
||||
@@ -217,18 +153,14 @@ static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __
|
||||
return entries;
|
||||
}
|
||||
|
||||
static inline void xsk_ring_cons__cancel(struct xsk_ring_cons *cons, __u32 nb)
|
||||
{
|
||||
cons->cached_cons -= nb;
|
||||
}
|
||||
|
||||
static inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, __u32 nb)
|
||||
static inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, size_t nb)
|
||||
{
|
||||
/* Make sure data has been read before indicating we are done
|
||||
* with the entries by updating the consumer pointer.
|
||||
*/
|
||||
libbpf_smp_store_release(cons->consumer, *cons->consumer + nb);
|
||||
libbpf_smp_rwmb();
|
||||
|
||||
*cons->consumer += nb;
|
||||
}
|
||||
|
||||
static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
||||
@@ -251,10 +183,8 @@ static inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)
|
||||
return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);
|
||||
}
|
||||
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__fd(const struct xsk_umem *umem);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
||||
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
|
||||
#define XSK_RING_CONS__DEFAULT_NUM_DESCS 2048
|
||||
#define XSK_RING_PROD__DEFAULT_NUM_DESCS 2048
|
||||
@@ -271,11 +201,6 @@ struct xsk_umem_config {
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_setup_xdp_prog(int ifindex, int *xsks_map_fd);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__update_xskmap(struct xsk_socket *xsk, int xsks_map_fd);
|
||||
|
||||
/* Flags for the libbpf_flags field. */
|
||||
#define XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD (1 << 0)
|
||||
|
||||
@@ -288,46 +213,31 @@ struct xsk_socket_config {
|
||||
};
|
||||
|
||||
/* Set config to NULL to get the default configuration. */
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__create(struct xsk_socket **xsk,
|
||||
const char *ifname, __u32 queue_id,
|
||||
struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
const struct xsk_socket_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
||||
const char *ifname,
|
||||
__u32 queue_id, struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_socket_config *config);
|
||||
LIBBPF_API int xsk_umem__create(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
||||
const char *ifname, __u32 queue_id,
|
||||
struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
const struct xsk_socket_config *config);
|
||||
|
||||
/* Returns 0 for success and -EBUSY if the umem is still in use. */
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__delete(struct xsk_umem *umem);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
void xsk_socket__delete(struct xsk_socket *xsk);
|
||||
LIBBPF_API int xsk_umem__delete(struct xsk_umem *umem);
|
||||
LIBBPF_API void xsk_socket__delete(struct xsk_socket *xsk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
||||
To: bpf@vger.kernel.org
|
||||
Cc: Alexei Starovoitov <ast@kernel.org>,
|
||||
Daniel Borkmann <daniel@iogearbox.net>,
|
||||
Andrii Nakryiko <andrii@kernel.org>
|
||||
Subject: [PATCH bpf-next] selftests/bpf: Fix OOB write in test_verifier
|
||||
Date: Tue, 14 Dec 2021 07:18:00 +0530 [thread overview]
|
||||
Message-ID: <20211214014800.78762-1-memxor@gmail.com> (raw)
|
||||
|
||||
The commit referenced below added fixup_map_timer support (to create a
|
||||
BPF map containing timers), but failed to increase the size of the
|
||||
map_fds array, leading to out of bounds write. Fix this by changing
|
||||
MAX_NR_MAPS to 22.
|
||||
|
||||
Fixes: e60e6962c503 ("selftests/bpf: Add tests for restricted helpers")
|
||||
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
|
||||
---
|
||||
tools/testing/selftests/bpf/test_verifier.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
|
||||
index ad5d30bafd93..33e2ecb3bef9 100644
|
||||
--- a/tools/testing/selftests/bpf/test_verifier.c
|
||||
+++ b/tools/testing/selftests/bpf/test_verifier.c
|
||||
@@ -54,7 +54,7 @@
|
||||
#define MAX_INSNS BPF_MAXINSNS
|
||||
#define MAX_TEST_INSNS 1000000
|
||||
#define MAX_FIXUPS 8
|
||||
-#define MAX_NR_MAPS 21
|
||||
+#define MAX_NR_MAPS 22
|
||||
#define MAX_TEST_RUNS 8
|
||||
#define POINTER_VALUE 0xcafe4all
|
||||
#define TEST_DATA_LEN 64
|
||||
--
|
||||
2.34.1
|
||||
@@ -6,7 +6,7 @@ CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
|
||||
ENV_VARS="${ENV_VARS:-}"
|
||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||
ADDITIONAL_DEPS=(clang pkg-config gcc-10)
|
||||
ADDITIONAL_DEPS=(clang pkg-config gcc-8)
|
||||
CFLAGS="-g -O2 -Werror -Wall"
|
||||
|
||||
function info() {
|
||||
@@ -18,10 +18,10 @@ function error() {
|
||||
}
|
||||
|
||||
function docker_exec() {
|
||||
docker exec $ENV_VARS $CONT_NAME "$@"
|
||||
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
||||
}
|
||||
|
||||
set -eu
|
||||
set -e
|
||||
|
||||
source "$(dirname $0)/travis_wait.bash"
|
||||
|
||||
@@ -31,6 +31,7 @@ for phase in "${PHASES[@]}"; do
|
||||
info "Setup phase"
|
||||
info "Using Debian $DEBIAN_RELEASE"
|
||||
|
||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
docker --version
|
||||
|
||||
docker pull debian:$DEBIAN_RELEASE
|
||||
@@ -38,24 +39,19 @@ for phase in "${PHASES[@]}"; do
|
||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||
-w /build --privileged=true --name $CONT_NAME \
|
||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||
echo -e "::group::Build Env Setup"
|
||||
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||
docker_exec apt-get -y update
|
||||
docker_exec apt-get -y install aptitude
|
||||
docker_exec aptitude -y build-dep libelf-dev
|
||||
docker_exec aptitude -y install libelf-dev
|
||||
docker_exec aptitude -y install "${ADDITIONAL_DEPS[@]}"
|
||||
echo -e "::endgroup::"
|
||||
docker_exec apt-get -y build-dep libelf-dev
|
||||
docker_exec apt-get -y install libelf-dev
|
||||
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
||||
;;
|
||||
RUN|RUN_CLANG|RUN_GCC10|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
||||
CC="cc"
|
||||
RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
||||
if [[ "$phase" = *"CLANG"* ]]; then
|
||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||
CC="clang"
|
||||
elif [[ "$phase" = *"GCC10"* ]]; then
|
||||
ENV_VARS="-e CC=gcc-10 -e CXX=g++-10"
|
||||
CC="gcc-10"
|
||||
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
||||
elif [[ "$phase" = *"GCC8"* ]]; then
|
||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
||||
CC="gcc-8"
|
||||
else
|
||||
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
||||
fi
|
||||
@@ -63,9 +59,9 @@ for phase in "${PHASES[@]}"; do
|
||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||
fi
|
||||
docker_exec mkdir build install
|
||||
docker_exec ${CC} --version
|
||||
docker_exec ${CC:-cc} --version
|
||||
info "build"
|
||||
docker_exec make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
docker_exec make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
info "ldd build/libbpf.so:"
|
||||
docker_exec ldd build/libbpf.so
|
||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||
@@ -74,8 +70,7 @@ for phase in "${PHASES[@]}"; do
|
||||
fi
|
||||
info "install"
|
||||
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||
info "link binary"
|
||||
docker_exec bash -c "CFLAGS=\"${CFLAGS}\" ./travis-ci/managers/test_compile.sh"
|
||||
docker_exec rm -rf build install
|
||||
;;
|
||||
CLEANUP)
|
||||
info "Cleanup phase"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euox pipefail
|
||||
|
||||
CFLAGS=${CFLAGS:-}
|
||||
|
||||
cat << EOF > main.c
|
||||
#include <bpf/libbpf.h>
|
||||
int main() {
|
||||
return bpf_object__open(0) < 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
# static linking
|
||||
${CC:-cc} ${CFLAGS} -o main -I./install/usr/include main.c ./build/libbpf.a -lelf -lz
|
||||
@@ -1,16 +1,20 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
set -e
|
||||
set -x
|
||||
|
||||
RELEASE="focal"
|
||||
RELEASE="bionic"
|
||||
|
||||
echo "deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse" >>/etc/apt/sources.list
|
||||
|
||||
apt-get update
|
||||
apt-get install -y pkg-config
|
||||
apt-get -y build-dep libelf-dev
|
||||
apt-get install -y libelf-dev pkg-config
|
||||
|
||||
source "$(dirname $0)/travis_wait.bash"
|
||||
|
||||
cd $REPO_ROOT
|
||||
|
||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined -Wno-stringop-truncation"
|
||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
||||
mkdir build install
|
||||
cc --version
|
||||
make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
@@ -20,4 +24,4 @@ if ! ldd build/libbpf.so | grep -q libelf; then
|
||||
exit 1
|
||||
fi
|
||||
make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||
CFLAGS=${CFLAGS} $(dirname $0)/test_compile.sh
|
||||
rm -rf build install
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
# This script builds a Debian root filesystem image for testing libbpf in a
|
||||
# virtual machine. Requires debootstrap >= 1.0.95 and zstd.
|
||||
|
||||
# Use e.g. ./mkrootfs_debian.sh --arch=s390x to generate a rootfs for a
|
||||
# foreign architecture. Requires configured binfmt_misc, e.g. using
|
||||
# Debian/Ubuntu's qemu-user-binfmt package or
|
||||
# https://github.com/multiarch/qemu-user-static.
|
||||
|
||||
set -e -u -x -o pipefail
|
||||
|
||||
# Check whether we are root now in order to avoid confusing errors later.
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "$0 must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a working directory and schedule its deletion.
|
||||
root=$(mktemp -d -p "$PWD")
|
||||
trap 'rm -r "$root"' EXIT
|
||||
|
||||
# Install packages.
|
||||
packages=binutils,busybox,elfutils,ethtool,iproute2,libcap2,libelf1,strace,zlib1g
|
||||
debootstrap --include="$packages" --variant=minbase "$@" bookworm "$root"
|
||||
|
||||
# Remove the init scripts (tests use their own). Also remove various
|
||||
# unnecessary files in order to save space.
|
||||
rm -rf \
|
||||
"$root"/etc/rcS.d \
|
||||
"$root"/usr/share/{doc,info,locale,man,zoneinfo} \
|
||||
"$root"/var/cache/apt/archives/* \
|
||||
"$root"/var/lib/apt/lists/*
|
||||
|
||||
# Save some more space by removing coreutils - the tests use busybox. Before
|
||||
# doing that, delete the buggy postrm script, which uses the rm command.
|
||||
rm -f "$root/var/lib/dpkg/info/coreutils.postrm"
|
||||
chroot "$root" dpkg --remove --force-remove-essential coreutils
|
||||
|
||||
# Apply common tweaks.
|
||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
||||
|
||||
# Save the result.
|
||||
name="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
||||
rm -f "$name"
|
||||
tar -C "$root" -c . | zstd -T0 -19 -o "$name"
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
# This script prepares a mounted root filesystem for testing libbpf in a virtual
|
||||
# machine.
|
||||
set -e -u -x -o pipefail
|
||||
root=$1
|
||||
shift
|
||||
|
||||
chroot "${root}" /bin/busybox --install
|
||||
|
||||
cat > "$root/etc/inittab" << "EOF"
|
||||
::sysinit:/etc/init.d/rcS
|
||||
::ctrlaltdel:/sbin/reboot
|
||||
::shutdown:/sbin/swapoff -a
|
||||
::shutdown:/bin/umount -a -r
|
||||
::restart:/sbin/init
|
||||
EOF
|
||||
chmod 644 "$root/etc/inittab"
|
||||
|
||||
mkdir -m 755 -p "$root/etc/init.d" "$root/etc/rcS.d"
|
||||
cat > "$root/etc/rcS.d/S10-mount" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
/bin/mount proc /proc -t proc
|
||||
|
||||
# Mount devtmpfs if not mounted
|
||||
if [[ -z $(/bin/mount -t devtmpfs) ]]; then
|
||||
/bin/mount devtmpfs /dev -t devtmpfs
|
||||
fi
|
||||
|
||||
/bin/mount sysfs /sys -t sysfs
|
||||
/bin/mount bpffs /sys/fs/bpf -t bpf
|
||||
/bin/mount debugfs /sys/kernel/debug -t debugfs
|
||||
|
||||
echo 'Listing currently mounted file systems'
|
||||
/bin/mount
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
||||
|
||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
ip link set lo up
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
||||
|
||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
for path in /etc/rcS.d/S*; do
|
||||
[ -x "$path" ] && "$path"
|
||||
done
|
||||
EOF
|
||||
chmod 755 "$root/etc/init.d/rcS"
|
||||
|
||||
chmod 755 "$root"
|
||||
@@ -1,107 +0,0 @@
|
||||
# IBM Z self-hosted builder
|
||||
|
||||
libbpf CI uses an IBM-provided z15 self-hosted builder. There are no IBM Z
|
||||
builds of GitHub (GH) Actions runner, and stable qemu-user has problems with .NET
|
||||
apps, so the builder runs the x86_64 runner version with qemu-user built from
|
||||
the master branch.
|
||||
|
||||
We are currently supporting runners for the following repositories:
|
||||
* libbpf/libbpf
|
||||
* kernel-patches/bpf
|
||||
* kernel-patches/vmtest
|
||||
|
||||
Below instructions are directly applicable to libbpf, and require minor
|
||||
modifications for kernel-patches repos. Currently, qemu-user-static Docker
|
||||
image is shared between all GitHub runners, but separate actions-runner-\*
|
||||
service / Docker image is created for each runner type.
|
||||
|
||||
## Configuring the builder.
|
||||
|
||||
### Install prerequisites.
|
||||
|
||||
```
|
||||
$ sudo apt install -y docker.io # Ubuntu
|
||||
```
|
||||
|
||||
### Add services.
|
||||
|
||||
```
|
||||
$ sudo cp *.service /etc/systemd/system/
|
||||
$ sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
### Create a config file.
|
||||
|
||||
```
|
||||
$ sudo tee /etc/actions-runner-libbpf
|
||||
repo=<owner>/<name>
|
||||
access_token=<ghp_***>
|
||||
```
|
||||
|
||||
Access token should have the repo scope, consult
|
||||
https://docs.github.com/en/rest/reference/actions#create-a-registration-token-for-a-repository
|
||||
for details.
|
||||
|
||||
### Autostart the x86_64 emulation support.
|
||||
|
||||
This step is important, you would not be able to build docker container
|
||||
without having this service running. If container build fails, make sure
|
||||
service is running properly.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now qemu-user-static
|
||||
```
|
||||
|
||||
### Autostart the runner.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Rebuilding the image
|
||||
|
||||
In order to update the `iiilinuxibmcom/actions-runner-libbpf` image, e.g. to
|
||||
get the latest OS security fixes, use the following commands:
|
||||
|
||||
```
|
||||
$ sudo docker build \
|
||||
--pull \
|
||||
-f actions-runner-libbpf.Dockerfile \
|
||||
-t iiilinuxibmcom/actions-runner-libbpf \
|
||||
.
|
||||
$ sudo systemctl restart actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Removing persistent data
|
||||
|
||||
The `actions-runner-libbpf` service stores various temporary data, such as
|
||||
runner registration information, work directories and logs, in the
|
||||
`actions-runner-libbpf` volume. In order to remove it and start from scratch,
|
||||
e.g. when upgrading the runner or switching it to a different repository, use
|
||||
the following commands:
|
||||
|
||||
```
|
||||
$ sudo systemctl stop actions-runner-libbpf
|
||||
$ sudo docker rm -f actions-runner-libbpf
|
||||
$ sudo docker volume rm actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
In order to check if service is running, use the following command:
|
||||
|
||||
```
|
||||
$ sudo systemctl status <service name>
|
||||
```
|
||||
|
||||
In order to get logs for service:
|
||||
|
||||
```
|
||||
$ journalctl -u <service name>
|
||||
```
|
||||
|
||||
In order to check which containers are currently active:
|
||||
|
||||
```
|
||||
$ sudo docker ps
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
# Self-Hosted IBM Z Github Actions Runner.
|
||||
|
||||
# Temporary image: amd64 dependencies.
|
||||
FROM amd64/ubuntu:20.04 as ld-prefix
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install ca-certificates libicu66 libssl1.1
|
||||
|
||||
# Main image.
|
||||
FROM s390x/ubuntu:20.04
|
||||
|
||||
# Packages for libbpf testing that are not installed by .github/actions/setup.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install \
|
||||
bc \
|
||||
bison \
|
||||
cmake \
|
||||
cpu-checker \
|
||||
curl \
|
||||
flex \
|
||||
git \
|
||||
jq \
|
||||
linux-image-generic \
|
||||
qemu-system-s390x \
|
||||
rsync \
|
||||
software-properties-common \
|
||||
sudo \
|
||||
tree
|
||||
|
||||
# amd64 dependencies.
|
||||
COPY --from=ld-prefix / /usr/x86_64-linux-gnu/
|
||||
RUN ln -fs ../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /usr/x86_64-linux-gnu/lib64/
|
||||
RUN ln -fs /etc/resolv.conf /usr/x86_64-linux-gnu/etc/
|
||||
ENV QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
||||
|
||||
# amd64 Github Actions Runner.
|
||||
ARG version=2.285.0
|
||||
RUN useradd -m actions-runner
|
||||
RUN echo "actions-runner ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
||||
RUN echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >>/etc/sudoers
|
||||
RUN usermod -a -G kvm actions-runner
|
||||
USER actions-runner
|
||||
ENV USER=actions-runner
|
||||
WORKDIR /home/actions-runner
|
||||
RUN curl -L https://github.com/actions/runner/releases/download/v${version}/actions-runner-linux-x64-${version}.tar.gz | tar -xz
|
||||
VOLUME /home/actions-runner
|
||||
|
||||
# Scripts.
|
||||
COPY fs/ /
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/usr/bin/actions-runner"]
|
||||
@@ -1,24 +0,0 @@
|
||||
[Unit]
|
||||
Description=Self-Hosted IBM Z Github Actions Runner
|
||||
Wants=qemu-user-static
|
||||
After=qemu-user-static
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--device=/dev/kvm \
|
||||
--env-file=/etc/actions-runner-libbpf \
|
||||
--init \
|
||||
--interactive \
|
||||
--name=actions-runner-libbpf \
|
||||
--rm \
|
||||
--volume=actions-runner-libbpf:/home/actions-runner \
|
||||
iiilinuxibmcom/actions-runner-libbpf
|
||||
ExecStop=/bin/sh -c "docker exec actions-runner-libbpf kill -INT -- -1"
|
||||
ExecStop=/bin/sh -c "docker wait actions-runner-libbpf"
|
||||
ExecStop=/bin/sh -c "docker rm actions-runner-libbpf"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Ephemeral runner startup script.
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
#
|
||||
# - repo=<owner>/<name>
|
||||
# - access_token=<ghp_***>
|
||||
#
|
||||
|
||||
set -e -u
|
||||
|
||||
# Check the cached registration token.
|
||||
token_file=registration-token.json
|
||||
set +e
|
||||
expires_at=$(jq --raw-output .expires_at "$token_file" 2>/dev/null)
|
||||
status=$?
|
||||
set -e
|
||||
if [[ $status -ne 0 || $(date +%s) -ge $(date -d "$expires_at" +%s) ]]; then
|
||||
# Refresh the cached registration token.
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $access_token" \
|
||||
"https://api.github.com/repos/$repo/actions/runners/registration-token" \
|
||||
-o "$token_file"
|
||||
fi
|
||||
|
||||
# (Re-)register the runner.
|
||||
registration_token=$(jq --raw-output .token "$token_file")
|
||||
./config.sh remove --token "$registration_token" || true
|
||||
./config.sh \
|
||||
--url "https://github.com/$repo" \
|
||||
--token "$registration_token" \
|
||||
--labels z15 \
|
||||
--ephemeral
|
||||
|
||||
# Run one job.
|
||||
./run.sh
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Container entrypoint that waits for all spawned processes.
|
||||
#
|
||||
|
||||
set -e -u
|
||||
|
||||
# /dev/kvm has host permissions, fix it.
|
||||
if [ -e /dev/kvm ]; then
|
||||
sudo chown root:kvm /dev/kvm
|
||||
fi
|
||||
|
||||
# Create a FIFO and start reading from its read end.
|
||||
tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX")
|
||||
trap 'rm -r "$tempdir"' EXIT
|
||||
done="$tempdir/pipe"
|
||||
mkfifo "$done"
|
||||
cat "$done" & waiter=$!
|
||||
|
||||
# Start the workload. Its descendants will inherit the FIFO's write end.
|
||||
status=0
|
||||
if [ "$#" -eq 0 ]; then
|
||||
bash 9>"$done" || status=$?
|
||||
else
|
||||
"$@" 9>"$done" || status=$?
|
||||
fi
|
||||
|
||||
# When the workload and all of its descendants exit, the FIFO's write end will
|
||||
# be closed and `cat "$done"` will exit. Wait until it happens. This is needed
|
||||
# in order to handle SelfUpdater, which the workload may start in background
|
||||
# before exiting.
|
||||
wait "$waiter"
|
||||
|
||||
exit "$status"
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Support for transparent execution of non-native binaries with QEMU user emulation
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# The source code for iiilinuxibmcom/qemu-user-static is at https://github.com/iii-i/qemu-user-static/tree/v6.1.0-1
|
||||
# TODO: replace it with multiarch/qemu-user-static once version >6.1 is available
|
||||
ExecStart=/usr/bin/docker run --rm --interactive --privileged iiilinuxibmcom/qemu-user-static --reset -p yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
25
travis-ci/vmtest/build_pahole.sh
Executable file
25
travis-ci/vmtest/build_pahole.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
CWD=$(pwd)
|
||||
REPO_PATH=$1
|
||||
PAHOLE_ORIGIN=https://git.kernel.org/pub/scm/devel/pahole/pahole.git
|
||||
|
||||
mkdir -p ${REPO_PATH}
|
||||
cd ${REPO_PATH}
|
||||
git init
|
||||
git remote add origin ${PAHOLE_ORIGIN}
|
||||
git fetch origin
|
||||
git checkout master
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -D__LIB=lib ..
|
||||
make -j$((4*$(nproc))) all
|
||||
sudo make install
|
||||
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/usr/local/lib
|
||||
ldd $(which pahole)
|
||||
pahole --version
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user