mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-22 17:29:07 +08:00
Compare commits
282 Commits
v0.3
...
v0.4.0_net
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aea40f7179 | ||
|
|
8bdc267e7b | ||
|
|
d0c398be4f | ||
|
|
7d9cc837ef | ||
|
|
a3c0cc19d4 | ||
|
|
7c6d34a2c9 | ||
|
|
a69c52bb11 | ||
|
|
6d67d53143 | ||
|
|
91259bc676 | ||
|
|
a3f8c5a306 | ||
|
|
d23679b415 | ||
|
|
9923f25600 | ||
|
|
40160ed4d4 | ||
|
|
7b22fc4cdb | ||
|
|
152882e17a | ||
|
|
0e7520949e | ||
|
|
c3f7daaab5 | ||
|
|
1a1e7a0612 | ||
|
|
827963ffb3 | ||
|
|
4ab24e7d62 | ||
|
|
b2a63c974d | ||
|
|
88649fe655 | ||
|
|
1778e0b1bd | ||
|
|
64f027efda | ||
|
|
6bf8babb33 | ||
|
|
70ad3e8314 | ||
|
|
dbdd8f3b34 | ||
|
|
52e96052a2 | ||
|
|
41db5534d8 | ||
|
|
54a7bc87d5 | ||
|
|
9979463ccf | ||
|
|
b91ca01922 | ||
|
|
8ded7c6db0 | ||
|
|
7df4ea0f0d | ||
|
|
02efadd0b0 | ||
|
|
02333ba360 | ||
|
|
2805c2a4ca | ||
|
|
6921017d25 | ||
|
|
e65d128903 | ||
|
|
512b472d97 | ||
|
|
73788dd22f | ||
|
|
a180eb551e | ||
|
|
9d2b7e471b | ||
|
|
3a0fc666ef | ||
|
|
7c25b1d569 | ||
|
|
d41e821ccf | ||
|
|
2fe57e40ac | ||
|
|
f81dbd3475 | ||
|
|
035fd6aca0 | ||
|
|
e44c8486c6 | ||
|
|
14f5433b2e | ||
|
|
d7a2de020b | ||
|
|
bb92e7ab4d | ||
|
|
3f22535d56 | ||
|
|
f8ab8bde8e | ||
|
|
506a544834 | ||
|
|
ec2c78c034 | ||
|
|
030ff87857 | ||
|
|
0db006d28e | ||
|
|
6e6f18ac5d | ||
|
|
deca7932c3 | ||
|
|
ebcae72279 | ||
|
|
64362b8896 | ||
|
|
df01b246df | ||
|
|
6eb5e25905 | ||
|
|
a603965dad | ||
|
|
f61c3b318b | ||
|
|
8235032464 | ||
|
|
dc2c53b7f6 | ||
|
|
fb3809e940 | ||
|
|
74d3571880 | ||
|
|
be570b29c1 | ||
|
|
9aa71e1040 | ||
|
|
b3ffd258fc | ||
|
|
4447ac82d4 | ||
|
|
8fa229c455 | ||
|
|
8a670b7422 | ||
|
|
21f90f61b0 | ||
|
|
c8b1d14b03 | ||
|
|
c0b2ceba1d | ||
|
|
bd25fc7df1 | ||
|
|
4920031c88 | ||
|
|
8fa50e86c1 | ||
|
|
330a158982 | ||
|
|
a524ae0bbf | ||
|
|
97e2a9c9a1 | ||
|
|
bef77595ca | ||
|
|
6f7839f477 | ||
|
|
90aba5e582 | ||
|
|
4dc3aeb072 | ||
|
|
4ce0551ee5 | ||
|
|
f8411901c4 | ||
|
|
9ff2b76693 | ||
|
|
df023f5cfc | ||
|
|
ae62c159ec | ||
|
|
8bf016110e | ||
|
|
d3e4039a0a | ||
|
|
dd34504b43 | ||
|
|
bec2ae0c6e | ||
|
|
1d6106cf45 | ||
|
|
95e51c1dbe | ||
|
|
db132757c9 | ||
|
|
41cddf18f4 | ||
|
|
f883bbf3f4 | ||
|
|
db8982bcaa | ||
|
|
d1571ab5ce | ||
|
|
03b0787342 | ||
|
|
a1bd8104a9 | ||
|
|
ccead28901 | ||
|
|
0b59d75ecd | ||
|
|
a5ee05d505 | ||
|
|
42ebbbce7d | ||
|
|
26497b9a88 | ||
|
|
5d5af3f07e | ||
|
|
899c45baa2 | ||
|
|
95008d47dd | ||
|
|
13acc0af00 | ||
|
|
1b9138e452 | ||
|
|
2da7f66d3f | ||
|
|
9d5ac4931d | ||
|
|
5bfbb36440 | ||
|
|
343f63e245 | ||
|
|
0dccb885a3 | ||
|
|
8e3a63ea48 | ||
|
|
7c7ba067fc | ||
|
|
12eb2666d9 | ||
|
|
234dea015b | ||
|
|
c3c2e52201 | ||
|
|
b79c698300 | ||
|
|
546199a723 | ||
|
|
b44566c71b | ||
|
|
594960b3db | ||
|
|
694a70c522 | ||
|
|
c96f2f1b29 | ||
|
|
ac2095783a | ||
|
|
fecf2cf6dd | ||
|
|
c1f36fb3e3 | ||
|
|
6eac86910c | ||
|
|
64a654f398 | ||
|
|
34eb4fb3f1 | ||
|
|
007709011e | ||
|
|
db9614b6bd | ||
|
|
57375504c6 | ||
|
|
d71ff87a2d | ||
|
|
01515b8f05 | ||
|
|
6028cec50c | ||
|
|
68695d0173 | ||
|
|
72cdd6ed42 | ||
|
|
b5bfbab488 | ||
|
|
1cf1c245d1 | ||
|
|
076dd5dadb | ||
|
|
6f585ab88f | ||
|
|
c5389a965b | ||
|
|
a58b8ca93e | ||
|
|
1691c37b39 | ||
|
|
242842b34c | ||
|
|
6b14cfa56e | ||
|
|
b8b1faa3d4 | ||
|
|
9e123fa5d2 | ||
|
|
4ccc1f0b9f | ||
|
|
b9278634aa | ||
|
|
af47e6c199 | ||
|
|
b2c06aec99 | ||
|
|
29e4840915 | ||
|
|
7078c5eae4 | ||
|
|
692ae888bc | ||
|
|
24b5d82967 | ||
|
|
4dcf439178 | ||
|
|
d9b9d4a43a | ||
|
|
7b106ea4b1 | ||
|
|
3319982d34 | ||
|
|
2e430712f5 | ||
|
|
120a21852b | ||
|
|
f4da689d90 | ||
|
|
30755d3a1c | ||
|
|
dda0dd6a87 | ||
|
|
c21f91bd35 | ||
|
|
552dec12dc | ||
|
|
678e8c8e49 | ||
|
|
f6de59dc3e | ||
|
|
823648416c | ||
|
|
02dbcbea28 | ||
|
|
a7502f2707 | ||
|
|
bab780e6f9 | ||
|
|
915f3abe94 | ||
|
|
0c248143d4 | ||
|
|
9f0e42b512 | ||
|
|
174d0b7b49 | ||
|
|
95f83b8b0c | ||
|
|
416343d95c | ||
|
|
4f932c1ee9 | ||
|
|
37e838f959 | ||
|
|
d98e968707 | ||
|
|
d4beac571a | ||
|
|
bea42d49f8 | ||
|
|
4e8d8d5cd2 | ||
|
|
8628610c32 | ||
|
|
2e51adc9bc | ||
|
|
1ccb9d99d6 | ||
|
|
90e052e6dd | ||
|
|
7ef7ed2a5d | ||
|
|
7036f3356e | ||
|
|
e5d7cbe15a | ||
|
|
e35afcb289 | ||
|
|
a18b72b920 | ||
|
|
2bd682d23e | ||
|
|
99bc176337 | ||
|
|
ea5752c641 | ||
|
|
1d2d2d0034 | ||
|
|
582b8fe21b | ||
|
|
3ea10e46cb | ||
|
|
3118d38a2e | ||
|
|
b09a4999d9 | ||
|
|
53f0e7d8ec | ||
|
|
d4d3a88b5a | ||
|
|
7b1f3e310b | ||
|
|
b156979d19 | ||
|
|
bd81770e10 | ||
|
|
4fdc36418d | ||
|
|
861ad35ceb | ||
|
|
7fc514acf1 | ||
|
|
74e94c40fe | ||
|
|
082a5c6020 | ||
|
|
75a2e3bda8 | ||
|
|
c8bfeae778 | ||
|
|
a0ad81d9c4 | ||
|
|
b727e2deca | ||
|
|
27db7104d5 | ||
|
|
c14f7e5dcf | ||
|
|
bbc65156d7 | ||
|
|
c903b3ab70 | ||
|
|
186ffbe0b5 | ||
|
|
1d483b45fc | ||
|
|
d64f8d3207 | ||
|
|
4f2e1ecbd9 | ||
|
|
21f523f235 | ||
|
|
18c0f03e2d | ||
|
|
fade1c32e6 | ||
|
|
8c2c7e5bcf | ||
|
|
092a606856 | ||
|
|
986962fade | ||
|
|
471e7c241d | ||
|
|
617f781804 | ||
|
|
473899d4f7 | ||
|
|
7e03685b8d | ||
|
|
7065a809fc | ||
|
|
18b55bc136 | ||
|
|
712f6587c9 | ||
|
|
60aa32b17a | ||
|
|
f3612e4117 | ||
|
|
587d2ab628 | ||
|
|
6cc16d6401 | ||
|
|
f0753b5259 | ||
|
|
642655629b | ||
|
|
14a61e86f0 | ||
|
|
d142d4a382 | ||
|
|
99e6a464b8 | ||
|
|
1015d47c2b | ||
|
|
06ee116fb1 | ||
|
|
e1a90f3768 | ||
|
|
f2a926ba46 | ||
|
|
b0b5ec0006 | ||
|
|
adaf538bca | ||
|
|
f35e87ddc4 | ||
|
|
767d82caab | ||
|
|
a199b85415 | ||
|
|
649f9dc746 | ||
|
|
eb56f8fb12 | ||
|
|
6e01a23cf6 | ||
|
|
16d7f413e2 | ||
|
|
f037b92465 | ||
|
|
4adbb7b2c7 | ||
|
|
d2b784d370 | ||
|
|
ac86f42e4a | ||
|
|
03fbe22a59 | ||
|
|
f15814c93a | ||
|
|
0db7da9a4a | ||
|
|
0de8b9a906 | ||
|
|
d52e5f5f88 | ||
|
|
a26ae1b254 | ||
|
|
c1d4bbb8c7 | ||
|
|
7c2a94f4f8 |
16
.github/actions/debian/action.yml
vendored
Normal file
16
.github/actions/debian/action.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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
Normal file
23
.github/actions/setup/action.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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 >> /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
|
||||||
|
|
||||||
35
.github/actions/vmtest/action.yml
vendored
Normal file
35
.github/actions/vmtest/action.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: 'vmtest'
|
||||||
|
description: 'Build + run vmtest'
|
||||||
|
inputs:
|
||||||
|
kernel:
|
||||||
|
description: 'kernel version or LATEST'
|
||||||
|
required: true
|
||||||
|
default: 'LATEST'
|
||||||
|
kernel-rev:
|
||||||
|
description: 'CHECKPOINT or rev/tag/branch'
|
||||||
|
required: true
|
||||||
|
default: 'CHECKPOINT'
|
||||||
|
kernel-origin:
|
||||||
|
description: 'kernel repo'
|
||||||
|
required: true
|
||||||
|
default: 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git'
|
||||||
|
pahole:
|
||||||
|
description: 'pahole rev/tag/branch'
|
||||||
|
required: true
|
||||||
|
default: 'master'
|
||||||
|
pahole-origin:
|
||||||
|
description: 'pahole repo'
|
||||||
|
required: true
|
||||||
|
default: 'https://git.kernel.org/pub/scm/devel/pahole/pahole.git'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- run: |
|
||||||
|
source /tmp/ci_setup
|
||||||
|
export KERNEL=${{ inputs.kernel }}
|
||||||
|
export KERNEL_BRANCH=${{ inputs.kernel-rev }}
|
||||||
|
export KERNEL_ORIGIN=${{ inputs.kernel-origin }}
|
||||||
|
export PAHOLE_BRANCH=${{ inputs.pahole }}
|
||||||
|
export PAHOLE_ORIGIN=${{ inputs.pahole-origin }}
|
||||||
|
$CI_ROOT/vmtest/run_vmtest.sh
|
||||||
|
shell: bash
|
||||||
30
.github/workflows/coverity.yml
vendored
Normal file
30
.github/workflows/coverity.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: libbpf-ci-coverity
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 18 * * *'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
coverity:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
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
Normal file
36
.github/workflows/ondemand.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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 }}
|
||||||
40
.github/workflows/pahole.yml
vendored
Normal file
40
.github/workflows/pahole.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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
|
||||||
|
- name: Get current pahole sha
|
||||||
|
id: current_sha
|
||||||
|
run:
|
||||||
|
git ls-remote https://git.kernel.org/pub/scm/devel/pahole/pahole.git $STAGING | awk '{print "::set-output name=sha::" $1}'
|
||||||
|
- name: Get latest result for this sha
|
||||||
|
id: latest
|
||||||
|
uses: pat-s/always-upload-cache@v2
|
||||||
|
with:
|
||||||
|
path: last_tested_pahole
|
||||||
|
key: ${{ steps.current_sha.outputs.sha }}
|
||||||
|
- name: Return cached test result
|
||||||
|
run: exit `cat last_tested_pahole || echo 1` # if file is empty that mean previous run timed out of canceled, returning failure
|
||||||
|
if: steps.latest.outputs.cache-hit == 'true'
|
||||||
|
- uses: ./.github/actions/vmtest
|
||||||
|
with:
|
||||||
|
kernel: LATEST
|
||||||
|
pahole: $STAGING
|
||||||
|
if: steps.latest.outputs.cache-hit != 'true'
|
||||||
|
- name: Save success
|
||||||
|
run: echo 0 > last_tested_pahole
|
||||||
|
if: steps.latest.outputs.cache-hit != 'true'
|
||||||
|
- name: Save failure
|
||||||
|
run: echo 1 > last_tested_pahole
|
||||||
|
if: ${{ failure() && steps.latest.outputs.cache-hit != 'true' }}
|
||||||
100
.github/workflows/test.yml
vendored
Normal file
100
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
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: ubuntu-latest
|
||||||
|
name: Kernel ${{ matrix.kernel }} + selftests
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- kernel: 'LATEST'
|
||||||
|
- kernel: '5.5.0'
|
||||||
|
- kernel: '4.9.0'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
name: Checkout
|
||||||
|
- uses: ./.github/actions/setup
|
||||||
|
name: Setup
|
||||||
|
- uses: ./.github/actions/vmtest
|
||||||
|
name: vmtest
|
||||||
|
with:
|
||||||
|
kernel: ${{ matrix.kernel }}
|
||||||
|
|
||||||
|
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
|
||||||
17
.readthedocs.yaml
Normal file
17
.readthedocs.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# .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
|
||||||
|
|
||||||
|
# Optionally set the version of Python and requirements required to build your docs
|
||||||
|
python:
|
||||||
|
version: 3.7
|
||||||
|
install:
|
||||||
|
- requirements: docs/sphinx/requirements.txt
|
||||||
32
.travis.yml
32
.travis.yml
@@ -1,6 +1,6 @@
|
|||||||
sudo: required
|
sudo: required
|
||||||
language: bash
|
language: bash
|
||||||
dist: bionic
|
dist: focal
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
@@ -36,7 +36,12 @@ stages:
|
|||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: Builds & Tests
|
- stage: Builds & Tests
|
||||||
name: Kernel LATEST + selftests
|
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
|
language: bash
|
||||||
env: KERNEL=LATEST
|
env: KERNEL=LATEST
|
||||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
||||||
@@ -46,11 +51,6 @@ jobs:
|
|||||||
env: KERNEL=4.9.0
|
env: KERNEL=4.9.0
|
||||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
|
script: $CI_ROOT/vmtest/run_vmtest.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: Debian Build
|
- name: Debian Build
|
||||||
language: bash
|
language: bash
|
||||||
install: $CI_ROOT/managers/debian.sh SETUP
|
install: $CI_ROOT/managers/debian.sh SETUP
|
||||||
@@ -75,33 +75,33 @@ jobs:
|
|||||||
script: $CI_ROOT/managers/debian.sh RUN_CLANG_ASAN || travis_terminate 1
|
script: $CI_ROOT/managers/debian.sh RUN_CLANG_ASAN || travis_terminate 1
|
||||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||||
|
|
||||||
- name: Debian Build (gcc-8)
|
- name: Debian Build (gcc-10)
|
||||||
language: bash
|
language: bash
|
||||||
install: $CI_ROOT/managers/debian.sh SETUP
|
install: $CI_ROOT/managers/debian.sh SETUP
|
||||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8 || travis_terminate 1
|
script: $CI_ROOT/managers/debian.sh RUN_GCC10 || travis_terminate 1
|
||||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||||
|
|
||||||
- name: Debian Build (gcc-8 ASan+UBSan)
|
- name: Debian Build (gcc-10 ASan+UBSan)
|
||||||
language: bash
|
language: bash
|
||||||
install: $CI_ROOT/managers/debian.sh SETUP
|
install: $CI_ROOT/managers/debian.sh SETUP
|
||||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8_ASAN || travis_terminate 1
|
script: $CI_ROOT/managers/debian.sh RUN_GCC10_ASAN || travis_terminate 1
|
||||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||||
|
|
||||||
- name: Ubuntu Bionic Build
|
- name: Ubuntu Focal Build
|
||||||
language: bash
|
language: bash
|
||||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||||
|
|
||||||
- name: Ubuntu Bionic Build (arm)
|
- name: Ubuntu Focal Build (arm)
|
||||||
arch: arm64
|
arch: arm64
|
||||||
language: bash
|
language: bash
|
||||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||||
|
|
||||||
- name: Ubuntu Bionic Build (s390x)
|
- name: Ubuntu Focal Build (s390x)
|
||||||
arch: s390x
|
arch: s390x
|
||||||
language: bash
|
language: bash
|
||||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||||
|
|
||||||
- name: Ubuntu Bionic Build (ppc64le)
|
- name: Ubuntu Focal Build (ppc64le)
|
||||||
arch: ppc64le
|
arch: ppc64le
|
||||||
language: bash
|
language: bash
|
||||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
|
||||||
@@ -120,7 +120,7 @@ jobs:
|
|||||||
- COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd src/"
|
- COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd src/"
|
||||||
- COVERITY_SCAN_BUILD_COMMAND="make"
|
- COVERITY_SCAN_BUILD_COMMAND="make"
|
||||||
install:
|
install:
|
||||||
- sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' >>/etc/apt/sources.list
|
- sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' >>/etc/apt/sources.list
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get -y build-dep libelf-dev
|
- sudo apt-get -y build-dep libelf-dev
|
||||||
- sudo apt-get install -y libelf-dev pkg-config
|
- sudo apt-get install -y libelf-dev pkg-config
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1a3449c19407a28f7019a887cdf0d6ba2444751a
|
3776f3517ed94d40ff0e3851d7ce2ce17b63099f
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3db1a3fa98808aa90f95ec3e0fa2fc7abf28f5c9
|
d20b41115ad53293201cc07ee429a38740cb056b
|
||||||
|
|||||||
36
README.md
36
README.md
@@ -1,3 +1,15 @@
|
|||||||
|
This is a mirror of [bpf-next Linux source
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
BPF/libbpf usage and questions
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
@@ -20,7 +32,7 @@ should be opened only for dealing with issues pertaining to specific way this
|
|||||||
libbpf mirror repo is set up and organized.
|
libbpf mirror repo is set up and organized.
|
||||||
|
|
||||||
Build
|
Build
|
||||||
[](https://travis-ci.com/github/libbpf/libbpf)
|
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
||||||
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
||||||
[](https://scan.coverity.com/projects/libbpf)
|
[](https://scan.coverity.com/projects/libbpf)
|
||||||
=====
|
=====
|
||||||
@@ -64,6 +76,7 @@ Distributions packaging libbpf from this mirror:
|
|||||||
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
- [Debian](https://packages.debian.org/source/sid/libbpf)
|
||||||
- [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
|
- [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
|
||||||
- [Ubuntu](https://packages.ubuntu.com/source/groovy/libbpf)
|
- [Ubuntu](https://packages.ubuntu.com/source/groovy/libbpf)
|
||||||
|
- [Alpine](https://pkgs.alpinelinux.org/packages?name=libbpf)
|
||||||
|
|
||||||
Benefits of packaging from the mirror over packaging from kernel sources:
|
Benefits of packaging from the mirror over packaging from kernel sources:
|
||||||
- Consistent versioning across distributions.
|
- Consistent versioning across distributions.
|
||||||
@@ -97,7 +110,9 @@ Some major Linux distributions come with kernel BTF already built in:
|
|||||||
- RHEL 8.2+
|
- RHEL 8.2+
|
||||||
- OpenSUSE Tumbleweed (in the next release, as of 2020-06-04)
|
- OpenSUSE Tumbleweed (in the next release, as of 2020-06-04)
|
||||||
- Arch Linux (from kernel 5.7.1.arch1-1)
|
- Arch Linux (from kernel 5.7.1.arch1-1)
|
||||||
|
- Manjaro (from kernel 5.4 if compiled after 2021-06-18)
|
||||||
- Ubuntu 20.10
|
- Ubuntu 20.10
|
||||||
|
- Debian 11 (amd64/arm64)
|
||||||
|
|
||||||
If your kernel doesn't come with BTF built-in, you'll need to build custom
|
If your kernel doesn't come with BTF built-in, you'll need to build custom
|
||||||
kernel. You'll need:
|
kernel. You'll need:
|
||||||
@@ -119,31 +134,18 @@ distributions have Clang/LLVM 10+ packaged by default:
|
|||||||
- Arch Linux
|
- Arch Linux
|
||||||
- Ubuntu 20.10 (LLVM 11)
|
- Ubuntu 20.10 (LLVM 11)
|
||||||
- Debian 11 (LLVM 11)
|
- Debian 11 (LLVM 11)
|
||||||
|
- Alpine 3.13+
|
||||||
|
|
||||||
Otherwise, please make sure to update it on your system.
|
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
|
The following resources are useful to understand what BPF CO-RE is and how to
|
||||||
use it:
|
use it:
|
||||||
- [BPF Portability and CO-RE](https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html)
|
- [BPF Portability and CO-RE](https://nakryiko.com/posts/bpf-portability-and-co-re/)
|
||||||
- [HOWTO: BCC to libbpf conversion](https://facebookmicrosites.github.io/bpf/blog/2020/02/20/bcc-to-libbpf-howto-guide.html)
|
- [HOWTO: BCC to libbpf conversion](https://nakryiko.com/posts/bcc-to-libbpf-howto-guide/)
|
||||||
- [libbpf-tools in BCC repo](https://github.com/iovisor/bcc/tree/master/libbpf-tools)
|
- [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
|
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
|
converting some more to both contribute to the BPF community and gain some
|
||||||
more experience with it.
|
more experience with it.
|
||||||
|
|
||||||
Details
|
|
||||||
=======
|
|
||||||
This is a mirror of [bpf-next Linux source
|
|
||||||
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.
|
|
||||||
|
|
||||||
Some header files in this repo (`include/linux/*.h`) are reduced versions of
|
|
||||||
their counterpart files at
|
|
||||||
[bpf-next](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/)'s
|
|
||||||
`tools/include/linux/*.h` to make compilation successful.
|
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
|
|||||||
2
docs/.gitignore
vendored
Normal file
2
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
sphinx/build
|
||||||
|
sphinx/doxygen/build
|
||||||
51
docs/api.rst
Normal file
51
docs/api.rst
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
.. _api:
|
||||||
|
|
||||||
|
.. toctree:: Table of Contents
|
||||||
|
|
||||||
|
|
||||||
|
LIBBPF API
|
||||||
|
==================
|
||||||
|
|
||||||
|
libbpf.h
|
||||||
|
--------
|
||||||
|
.. doxygenfile:: libbpf.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
bpf.h
|
||||||
|
-----
|
||||||
|
.. doxygenfile:: bpf.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
btf.h
|
||||||
|
-----
|
||||||
|
.. doxygenfile:: btf.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
xsk.h
|
||||||
|
-----
|
||||||
|
.. doxygenfile:: xsk.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
bpf_tracing.h
|
||||||
|
-------------
|
||||||
|
.. doxygenfile:: bpf_tracing.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
bpf_core_read.h
|
||||||
|
---------------
|
||||||
|
.. doxygenfile:: bpf_core_read.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
|
|
||||||
|
bpf_endian.h
|
||||||
|
------------
|
||||||
|
.. doxygenfile:: bpf_endian.h
|
||||||
|
:project: libbpf
|
||||||
|
:sections: func define public-type
|
||||||
40
docs/conf.py
Normal file
40
docs/conf.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/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
|
||||||
22
docs/index.rst
Normal file
22
docs/index.rst
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
libbpf
|
||||||
|
======
|
||||||
|
|
||||||
|
For API documentation see the `versioned API documentation site <https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
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.
|
||||||
37
docs/libbpf_build.rst
Normal file
37
docs/libbpf_build.rst
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.. 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,7 +1,7 @@
|
|||||||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
libbpf API naming convention
|
API naming convention
|
||||||
============================
|
=====================
|
||||||
|
|
||||||
libbpf API provides access to a few logically separated groups of
|
libbpf API provides access to a few logically separated groups of
|
||||||
functions and types. Every group has its own naming convention
|
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
|
All types and functions provided by libbpf API should have one of the
|
||||||
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
|
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
|
||||||
``perf_buffer_``.
|
``btf_dump_``, ``ring_buffer_``, ``perf_buffer_``.
|
||||||
|
|
||||||
System call wrappers
|
System call wrappers
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
System call wrappers are simple wrappers for commands supported by
|
System call wrappers are simple wrappers for commands supported by
|
||||||
sys_bpf system call. These wrappers should go to ``bpf.h`` header file
|
sys_bpf system call. These wrappers should go to ``bpf.h`` header file
|
||||||
and map one-on-one to corresponding commands.
|
and map one to one to corresponding commands.
|
||||||
|
|
||||||
For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
|
For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
|
||||||
command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
|
command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
|
||||||
@@ -49,10 +49,6 @@ object, ``bpf_object``, double underscore and ``open`` that defines the
|
|||||||
purpose of the function to open ELF file and create ``bpf_object`` from
|
purpose of the function to open ELF file and create ``bpf_object`` from
|
||||||
it.
|
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
|
All objects and corresponding functions other than BTF related should go
|
||||||
to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
|
to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
|
||||||
|
|
||||||
@@ -72,12 +68,8 @@ of both low-level ring access functions and high-level configuration
|
|||||||
functions. These can be mixed and matched. Note that these functions
|
functions. These can be mixed and matched. Note that these functions
|
||||||
are not reentrant for performance reasons.
|
are not reentrant for performance reasons.
|
||||||
|
|
||||||
Please take a look at Documentation/networking/af_xdp.rst in the Linux
|
ABI
|
||||||
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
|
libbpf can be both linked statically or used as DSO. To avoid possible
|
||||||
conflicts with other libraries an application is linked with, all
|
conflicts with other libraries an application is linked with, all
|
||||||
@@ -116,7 +108,8 @@ This bump in ABI version is at most once per kernel development cycle.
|
|||||||
|
|
||||||
For example, if current state of ``libbpf.map`` is:
|
For example, if current state of ``libbpf.map`` is:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: none
|
||||||
|
|
||||||
LIBBPF_0.0.1 {
|
LIBBPF_0.0.1 {
|
||||||
global:
|
global:
|
||||||
bpf_func_a;
|
bpf_func_a;
|
||||||
@@ -128,7 +121,8 @@ For example, if current state of ``libbpf.map`` is:
|
|||||||
, and a new symbol ``bpf_func_c`` is being introduced, then
|
, and a new symbol ``bpf_func_c`` is being introduced, then
|
||||||
``libbpf.map`` should be changed like this:
|
``libbpf.map`` should be changed like this:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block:: none
|
||||||
|
|
||||||
LIBBPF_0.0.1 {
|
LIBBPF_0.0.1 {
|
||||||
global:
|
global:
|
||||||
bpf_func_a;
|
bpf_func_a;
|
||||||
@@ -148,7 +142,7 @@ Format of version script and ways to handle ABI changes, including
|
|||||||
incompatible ones, described in details in [1].
|
incompatible ones, described in details in [1].
|
||||||
|
|
||||||
Stand-alone build
|
Stand-alone build
|
||||||
=================
|
-------------------
|
||||||
|
|
||||||
Under https://github.com/libbpf/libbpf there is a (semi-)automated
|
Under https://github.com/libbpf/libbpf there is a (semi-)automated
|
||||||
mirror of the mainline's version of libbpf for a stand-alone build.
|
mirror of the mainline's version of libbpf for a stand-alone build.
|
||||||
@@ -157,12 +151,12 @@ However, all changes to libbpf's code base must be upstreamed through
|
|||||||
the mainline kernel tree.
|
the mainline kernel tree.
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
-------------------
|
||||||
|
|
||||||
libbpf is dual-licensed under LGPL 2.1 and BSD 2-Clause.
|
libbpf is dual-licensed under LGPL 2.1 and BSD 2-Clause.
|
||||||
|
|
||||||
Links
|
Links
|
||||||
=====
|
-------------------
|
||||||
|
|
||||||
[1] https://www.akkadia.org/drepper/dsohowto.pdf
|
[1] https://www.akkadia.org/drepper/dsohowto.pdf
|
||||||
(Chapter 3. Maintaining APIs and ABIs).
|
(Chapter 3. Maintaining APIs and ABIs).
|
||||||
9
docs/sphinx/Makefile
Normal file
9
docs/sphinx/Makefile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = ../src
|
||||||
|
BUILDDIR = build
|
||||||
|
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)"
|
||||||
|
|
||||||
|
%:
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)"
|
||||||
277
docs/sphinx/doxygen/Doxyfile
Normal file
277
docs/sphinx/doxygen/Doxyfile
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
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
docs/sphinx/requirements.txt
Normal file
1
docs/sphinx/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
breathe
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ struct btf_type {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
|
||||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||||
|
|
||||||
@@ -72,7 +72,8 @@ struct btf_type {
|
|||||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||||
#define BTF_KIND_VAR 14 /* Variable */
|
#define BTF_KIND_VAR 14 /* Variable */
|
||||||
#define BTF_KIND_DATASEC 15 /* Section */
|
#define BTF_KIND_DATASEC 15 /* Section */
|
||||||
#define BTF_KIND_MAX BTF_KIND_DATASEC
|
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||||
|
#define BTF_KIND_MAX BTF_KIND_FLOAT
|
||||||
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
|
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
|
||||||
|
|
||||||
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
||||||
|
|||||||
@@ -653,6 +653,7 @@ enum {
|
|||||||
IFLA_BOND_AD_ACTOR_SYSTEM,
|
IFLA_BOND_AD_ACTOR_SYSTEM,
|
||||||
IFLA_BOND_TLB_DYNAMIC_LB,
|
IFLA_BOND_TLB_DYNAMIC_LB,
|
||||||
IFLA_BOND_PEER_NOTIF_DELAY,
|
IFLA_BOND_PEER_NOTIF_DELAY,
|
||||||
|
IFLA_BOND_AD_LACP_ACTIVE,
|
||||||
__IFLA_BOND_MAX,
|
__IFLA_BOND_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
612
include/uapi/linux/pkt_cls.h
Normal file
612
include/uapi/linux/pkt_cls.h
Normal file
@@ -0,0 +1,612 @@
|
|||||||
|
/* 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
|
||||||
1164
include/uapi/linux/pkt_sched.h
Normal file
1164
include/uapi/linux/pkt_sched.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -45,11 +45,14 @@ PATH_MAP=( \
|
|||||||
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||||
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||||
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||||
|
[tools/include/uapi/linux/pkt_cls.h]=include/uapi/linux/pkt_cls.h \
|
||||||
|
[tools/include/uapi/linux/pkt_sched.h]=include/uapi/linux/pkt_sched.h \
|
||||||
|
[Documentation/bpf/libbpf]=docs \
|
||||||
)
|
)
|
||||||
|
|
||||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
|
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore :^tools/include/tools/libc_compat.h"
|
||||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$'
|
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$|^docs/(\.gitignore|api\.rst|conf\.py)$|^docs/sphinx/.*'
|
||||||
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
LINUX_VIEW_EXCLUDE_REGEX='^include/tools/libc_compat.h$'
|
||||||
|
|
||||||
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
||||||
@@ -266,12 +269,12 @@ for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Generate bpf_helper_defs.h and commit, if anything changed
|
# Generate bpf_helper_defs.h and commit, if anything changed
|
||||||
# restore Linux tip to use bpf_helpers_doc.py
|
# restore Linux tip to use bpf_doc.py
|
||||||
cd_to ${LINUX_REPO}
|
cd_to ${LINUX_REPO}
|
||||||
git checkout ${TIP_TAG}
|
git checkout ${TIP_TAG}
|
||||||
# re-generate bpf_helper_defs.h
|
# re-generate bpf_helper_defs.h
|
||||||
cd_to ${LIBBPF_REPO}
|
cd_to ${LIBBPF_REPO}
|
||||||
"${LINUX_ABS_DIR}/scripts/bpf_helpers_doc.py" --header \
|
"${LINUX_ABS_DIR}/scripts/bpf_doc.py" --header \
|
||||||
--file include/uapi/linux/bpf.h > src/bpf_helper_defs.h
|
--file include/uapi/linux/bpf.h > src/bpf_helper_defs.h
|
||||||
# if anything changed, commit it
|
# if anything changed, commit it
|
||||||
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
helpers_changes=$(git status --porcelain src/bpf_helper_defs.h | wc -l)
|
||||||
|
|||||||
13
src/Makefile
13
src/Makefile
@@ -36,7 +36,8 @@ SHARED_OBJDIR := $(OBJDIR)/sharedobjs
|
|||||||
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
||||||
btf_dump.o hashmap.o ringbuf.o
|
btf_dump.o hashmap.o ringbuf.o strset.o linker.o gen_loader.o \
|
||||||
|
relo_core.o
|
||||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||||
|
|
||||||
@@ -48,9 +49,9 @@ ifndef BUILD_STATIC_ONLY
|
|||||||
VERSION_SCRIPT := libbpf.map
|
VERSION_SCRIPT := libbpf.map
|
||||||
endif
|
endif
|
||||||
|
|
||||||
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h \
|
HEADERS := bpf.h libbpf.h btf.h libbpf_common.h libbpf_legacy.h xsk.h \
|
||||||
bpf_helpers.h bpf_helper_defs.h bpf_tracing.h \
|
bpf_helpers.h bpf_helper_defs.h bpf_tracing.h \
|
||||||
bpf_endian.h bpf_core_read.h libbpf_common.h
|
bpf_endian.h bpf_core_read.h skel_internal.h
|
||||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
||||||
bpf.h bpf_common.h btf.h)
|
bpf.h bpf_common.h btf.h)
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ INSTALL = install
|
|||||||
|
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
|
|
||||||
ifeq ($(shell uname -m),x86_64)
|
ifeq ($(filter-out %64 %64be %64eb %64le %64el s390x, $(shell uname -m)),)
|
||||||
LIBSUBDIR := lib64
|
LIBSUBDIR := lib64
|
||||||
else
|
else
|
||||||
LIBSUBDIR := lib
|
LIBSUBDIR := lib
|
||||||
@@ -121,7 +122,7 @@ define do_install
|
|||||||
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||||
fi;
|
fi;
|
||||||
$(Q)$(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR)$2'
|
$(Q)$(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR)$2'
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# Preserve symlinks at installation.
|
# Preserve symlinks at installation.
|
||||||
@@ -130,7 +131,7 @@ define do_s_install
|
|||||||
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
$(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||||
fi;
|
fi;
|
||||||
$(Q)cp -fpR $1 '$(DESTDIR)$2'
|
$(Q)cp -fR $1 '$(DESTDIR)$2'
|
||||||
endef
|
endef
|
||||||
|
|
||||||
install: all install_headers install_pkgconfig
|
install: all install_headers install_pkgconfig
|
||||||
|
|||||||
231
src/bpf.c
231
src/bpf.c
@@ -80,6 +80,7 @@ static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size)
|
|||||||
int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, '\0', sizeof(attr));
|
memset(&attr, '\0', sizeof(attr));
|
||||||
|
|
||||||
@@ -102,7 +103,8 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
|||||||
else
|
else
|
||||||
attr.inner_map_fd = create_attr->inner_map_fd;
|
attr.inner_map_fd = create_attr->inner_map_fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
|
int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
|
||||||
@@ -160,6 +162,7 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name,
|
|||||||
__u32 map_flags, int node)
|
__u32 map_flags, int node)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, '\0', sizeof(attr));
|
memset(&attr, '\0', sizeof(attr));
|
||||||
|
|
||||||
@@ -178,7 +181,8 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name,
|
|||||||
attr.numa_node = node;
|
attr.numa_node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
|
int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
|
||||||
@@ -222,10 +226,10 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
|||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (!load_attr->log_buf != !load_attr->log_buf_sz)
|
if (!load_attr->log_buf != !load_attr->log_buf_sz)
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
if (load_attr->log_level > (4 | 2 | 1) || (load_attr->log_level && !load_attr->log_buf))
|
if (load_attr->log_level > (4 | 2 | 1) || (load_attr->log_level && !load_attr->log_buf))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.prog_type = load_attr->prog_type;
|
attr.prog_type = load_attr->prog_type;
|
||||||
@@ -281,8 +285,10 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
|||||||
load_attr->func_info_cnt,
|
load_attr->func_info_cnt,
|
||||||
load_attr->func_info_rec_size,
|
load_attr->func_info_rec_size,
|
||||||
attr.func_info_rec_size);
|
attr.func_info_rec_size);
|
||||||
if (!finfo)
|
if (!finfo) {
|
||||||
|
errno = E2BIG;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
attr.func_info = ptr_to_u64(finfo);
|
attr.func_info = ptr_to_u64(finfo);
|
||||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||||
@@ -293,8 +299,10 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
|||||||
load_attr->line_info_cnt,
|
load_attr->line_info_cnt,
|
||||||
load_attr->line_info_rec_size,
|
load_attr->line_info_rec_size,
|
||||||
attr.line_info_rec_size);
|
attr.line_info_rec_size);
|
||||||
if (!linfo)
|
if (!linfo) {
|
||||||
|
errno = E2BIG;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
attr.line_info = ptr_to_u64(linfo);
|
attr.line_info = ptr_to_u64(linfo);
|
||||||
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||||
@@ -318,9 +326,10 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
|||||||
|
|
||||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||||
done:
|
done:
|
||||||
|
/* free() doesn't affect errno, so we don't need to restore it */
|
||||||
free(finfo);
|
free(finfo);
|
||||||
free(linfo);
|
free(linfo);
|
||||||
return fd;
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||||
@@ -329,7 +338,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
struct bpf_prog_load_params p = {};
|
struct bpf_prog_load_params p = {};
|
||||||
|
|
||||||
if (!load_attr || !log_buf != !log_buf_sz)
|
if (!load_attr || !log_buf != !log_buf_sz)
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
p.prog_type = load_attr->prog_type;
|
p.prog_type = load_attr->prog_type;
|
||||||
p.expected_attach_type = load_attr->expected_attach_type;
|
p.expected_attach_type = load_attr->expected_attach_type;
|
||||||
@@ -391,6 +400,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
|||||||
int log_level)
|
int log_level)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.prog_type = type;
|
attr.prog_type = type;
|
||||||
@@ -404,13 +414,15 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
|||||||
attr.kern_version = kern_version;
|
attr.kern_version = kern_version;
|
||||||
attr.prog_flags = prog_flags;
|
attr.prog_flags = prog_flags;
|
||||||
|
|
||||||
return sys_bpf_prog_load(&attr, sizeof(attr));
|
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_update_elem(int fd, const void *key, const void *value,
|
int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||||
__u64 flags)
|
__u64 flags)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
@@ -418,22 +430,54 @@ int bpf_map_update_elem(int fd, const void *key, const void *value,
|
|||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_elem(int fd, const void *key, void *value)
|
int bpf_map_lookup_elem(int fd, const void *key, void *value)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_lookup_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
int bpf_map_lookup_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
||||||
|
{
|
||||||
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.map_fd = fd;
|
||||||
|
attr.key = ptr_to_u64(key);
|
||||||
|
attr.value = ptr_to_u64(value);
|
||||||
|
attr.flags = flags;
|
||||||
|
|
||||||
|
ret = sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
||||||
|
{
|
||||||
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
attr.map_fd = fd;
|
||||||
|
attr.key = ptr_to_u64(key);
|
||||||
|
attr.value = ptr_to_u64(value);
|
||||||
|
|
||||||
|
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
|
||||||
@@ -443,52 +487,46 @@ int bpf_map_lookup_elem_flags(int fd, const void *key, void *value, __u64 flags)
|
|||||||
attr.value = ptr_to_u64(value);
|
attr.value = ptr_to_u64(value);
|
||||||
attr.flags = flags;
|
attr.flags = flags;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
|
||||||
}
|
|
||||||
|
|
||||||
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
|
||||||
{
|
|
||||||
union bpf_attr attr;
|
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
|
||||||
attr.map_fd = fd;
|
|
||||||
attr.key = ptr_to_u64(key);
|
|
||||||
attr.value = ptr_to_u64(value);
|
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_delete_elem(int fd, const void *key)
|
int bpf_map_delete_elem(int fd, const void *key)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_get_next_key(int fd, const void *key, void *next_key)
|
int bpf_map_get_next_key(int fd, const void *key, void *next_key)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
attr.key = ptr_to_u64(key);
|
attr.key = ptr_to_u64(key);
|
||||||
attr.next_key = ptr_to_u64(next_key);
|
attr.next_key = ptr_to_u64(next_key);
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_freeze(int fd)
|
int bpf_map_freeze(int fd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_fd = fd;
|
attr.map_fd = fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
||||||
@@ -500,7 +538,7 @@ static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_map_batch_opts))
|
if (!OPTS_VALID(opts, bpf_map_batch_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.batch.map_fd = fd;
|
attr.batch.map_fd = fd;
|
||||||
@@ -515,7 +553,7 @@ static int bpf_map_batch_common(int cmd, int fd, void *in_batch,
|
|||||||
ret = sys_bpf(cmd, &attr, sizeof(attr));
|
ret = sys_bpf(cmd, &attr, sizeof(attr));
|
||||||
*count = attr.batch.count;
|
*count = attr.batch.count;
|
||||||
|
|
||||||
return ret;
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_delete_batch(int fd, void *keys, __u32 *count,
|
int bpf_map_delete_batch(int fd, void *keys, __u32 *count,
|
||||||
@@ -552,22 +590,26 @@ int bpf_map_update_batch(int fd, void *keys, void *values, __u32 *count,
|
|||||||
int bpf_obj_pin(int fd, const char *pathname)
|
int bpf_obj_pin(int fd, const char *pathname)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
attr.bpf_fd = fd;
|
attr.bpf_fd = fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_OBJ_PIN, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_obj_get(const char *pathname)
|
int bpf_obj_get(const char *pathname)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.pathname = ptr_to_u64((void *)pathname);
|
attr.pathname = ptr_to_u64((void *)pathname);
|
||||||
|
|
||||||
return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
|
||||||
@@ -585,9 +627,10 @@ int bpf_prog_attach_xattr(int prog_fd, int target_fd,
|
|||||||
const struct bpf_prog_attach_opts *opts)
|
const struct bpf_prog_attach_opts *opts)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
if (!OPTS_VALID(opts, bpf_prog_attach_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
@@ -596,30 +639,35 @@ int bpf_prog_attach_xattr(int prog_fd, int target_fd,
|
|||||||
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
attr.attach_flags = OPTS_GET(opts, flags, 0);
|
||||||
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
attr.replace_bpf_fd = OPTS_GET(opts, replace_prog_fd, 0);
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
attr.attach_type = type;
|
attr.attach_type = type;
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.target_fd = target_fd;
|
attr.target_fd = target_fd;
|
||||||
attr.attach_bpf_fd = prog_fd;
|
attr.attach_bpf_fd = prog_fd;
|
||||||
attr.attach_type = type;
|
attr.attach_type = type;
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_create(int prog_fd, int target_fd,
|
int bpf_link_create(int prog_fd, int target_fd,
|
||||||
@@ -628,15 +676,21 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
{
|
{
|
||||||
__u32 target_btf_id, iter_info_len;
|
__u32 target_btf_id, iter_info_len;
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_link_create_opts))
|
if (!OPTS_VALID(opts, bpf_link_create_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
iter_info_len = OPTS_GET(opts, iter_info_len, 0);
|
iter_info_len = OPTS_GET(opts, iter_info_len, 0);
|
||||||
target_btf_id = OPTS_GET(opts, target_btf_id, 0);
|
target_btf_id = OPTS_GET(opts, target_btf_id, 0);
|
||||||
|
|
||||||
if (iter_info_len && target_btf_id)
|
/* validate we don't have unexpected combinations of non-zero fields */
|
||||||
return -EINVAL;
|
if (iter_info_len || target_btf_id) {
|
||||||
|
if (iter_info_len && target_btf_id)
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
if (!OPTS_ZEROED(opts, target_btf_id))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.link_create.prog_fd = prog_fd;
|
attr.link_create.prog_fd = prog_fd;
|
||||||
@@ -644,34 +698,51 @@ int bpf_link_create(int prog_fd, int target_fd,
|
|||||||
attr.link_create.attach_type = attach_type;
|
attr.link_create.attach_type = attach_type;
|
||||||
attr.link_create.flags = OPTS_GET(opts, flags, 0);
|
attr.link_create.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
if (iter_info_len) {
|
if (target_btf_id) {
|
||||||
attr.link_create.iter_info =
|
|
||||||
ptr_to_u64(OPTS_GET(opts, iter_info, (void *)0));
|
|
||||||
attr.link_create.iter_info_len = iter_info_len;
|
|
||||||
} else if (target_btf_id) {
|
|
||||||
attr.link_create.target_btf_id = target_btf_id;
|
attr.link_create.target_btf_id = target_btf_id;
|
||||||
|
goto proceed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
|
switch (attach_type) {
|
||||||
|
case BPF_TRACE_ITER:
|
||||||
|
attr.link_create.iter_info = ptr_to_u64(OPTS_GET(opts, iter_info, (void *)0));
|
||||||
|
attr.link_create.iter_info_len = iter_info_len;
|
||||||
|
break;
|
||||||
|
case BPF_PERF_EVENT:
|
||||||
|
attr.link_create.perf_event.bpf_cookie = OPTS_GET(opts, perf_event.bpf_cookie, 0);
|
||||||
|
if (!OPTS_ZEROED(opts, perf_event))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!OPTS_ZEROED(opts, flags))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
proceed:
|
||||||
|
fd = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_detach(int link_fd)
|
int bpf_link_detach(int link_fd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.link_detach.link_fd = link_fd;
|
attr.link_detach.link_fd = link_fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_LINK_DETACH, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_LINK_DETACH, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_update(int link_fd, int new_prog_fd,
|
int bpf_link_update(int link_fd, int new_prog_fd,
|
||||||
const struct bpf_link_update_opts *opts)
|
const struct bpf_link_update_opts *opts)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.link_update.link_fd = link_fd;
|
attr.link_update.link_fd = link_fd;
|
||||||
@@ -679,17 +750,20 @@ int bpf_link_update(int link_fd, int new_prog_fd,
|
|||||||
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
||||||
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||||
|
|
||||||
return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_iter_create(int link_fd)
|
int bpf_iter_create(int link_fd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.iter_create.link_fd = link_fd;
|
attr.iter_create.link_fd = link_fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_ITER_CREATE, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_ITER_CREATE, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
|
int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
|
||||||
@@ -706,10 +780,12 @@ int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
|
|||||||
attr.query.prog_ids = ptr_to_u64(prog_ids);
|
attr.query.prog_ids = ptr_to_u64(prog_ids);
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_QUERY, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_QUERY, &attr, sizeof(attr));
|
||||||
|
|
||||||
if (attach_flags)
|
if (attach_flags)
|
||||||
*attach_flags = attr.query.attach_flags;
|
*attach_flags = attr.query.attach_flags;
|
||||||
*prog_cnt = attr.query.prog_cnt;
|
*prog_cnt = attr.query.prog_cnt;
|
||||||
return ret;
|
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
|
int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
|
||||||
@@ -727,13 +803,15 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
|
|||||||
attr.test.repeat = repeat;
|
attr.test.repeat = repeat;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
||||||
|
|
||||||
if (size_out)
|
if (size_out)
|
||||||
*size_out = attr.test.data_size_out;
|
*size_out = attr.test.data_size_out;
|
||||||
if (retval)
|
if (retval)
|
||||||
*retval = attr.test.retval;
|
*retval = attr.test.retval;
|
||||||
if (duration)
|
if (duration)
|
||||||
*duration = attr.test.duration;
|
*duration = attr.test.duration;
|
||||||
return ret;
|
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
||||||
@@ -742,7 +820,7 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!test_attr->data_out && test_attr->data_size_out > 0)
|
if (!test_attr->data_out && test_attr->data_size_out > 0)
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.test.prog_fd = test_attr->prog_fd;
|
attr.test.prog_fd = test_attr->prog_fd;
|
||||||
@@ -757,11 +835,13 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
|||||||
attr.test.repeat = test_attr->repeat;
|
attr.test.repeat = test_attr->repeat;
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
||||||
|
|
||||||
test_attr->data_size_out = attr.test.data_size_out;
|
test_attr->data_size_out = attr.test.data_size_out;
|
||||||
test_attr->ctx_size_out = attr.test.ctx_size_out;
|
test_attr->ctx_size_out = attr.test.ctx_size_out;
|
||||||
test_attr->retval = attr.test.retval;
|
test_attr->retval = attr.test.retval;
|
||||||
test_attr->duration = attr.test.duration;
|
test_attr->duration = attr.test.duration;
|
||||||
return ret;
|
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
||||||
@@ -770,7 +850,7 @@ int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_test_run_opts))
|
if (!OPTS_VALID(opts, bpf_test_run_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.test.prog_fd = prog_fd;
|
attr.test.prog_fd = prog_fd;
|
||||||
@@ -788,11 +868,13 @@ int bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts *opts)
|
|||||||
attr.test.data_out = ptr_to_u64(OPTS_GET(opts, data_out, NULL));
|
attr.test.data_out = ptr_to_u64(OPTS_GET(opts, data_out, NULL));
|
||||||
|
|
||||||
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
||||||
|
|
||||||
OPTS_SET(opts, data_size_out, attr.test.data_size_out);
|
OPTS_SET(opts, data_size_out, attr.test.data_size_out);
|
||||||
OPTS_SET(opts, ctx_size_out, attr.test.ctx_size_out);
|
OPTS_SET(opts, ctx_size_out, attr.test.ctx_size_out);
|
||||||
OPTS_SET(opts, duration, attr.test.duration);
|
OPTS_SET(opts, duration, attr.test.duration);
|
||||||
OPTS_SET(opts, retval, attr.test.retval);
|
OPTS_SET(opts, retval, attr.test.retval);
|
||||||
return ret;
|
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
||||||
@@ -807,7 +889,7 @@ static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
|||||||
if (!err)
|
if (!err)
|
||||||
*next_id = attr.next_id;
|
*next_id = attr.next_id;
|
||||||
|
|
||||||
return err;
|
return libbpf_err_errno(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
@@ -833,41 +915,49 @@ int bpf_link_get_next_id(__u32 start_id, __u32 *next_id)
|
|||||||
int bpf_prog_get_fd_by_id(__u32 id)
|
int bpf_prog_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.prog_id = id;
|
attr.prog_id = id;
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_get_fd_by_id(__u32 id)
|
int bpf_map_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.map_id = id;
|
attr.map_id = id;
|
||||||
|
|
||||||
return sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_btf_get_fd_by_id(__u32 id)
|
int bpf_btf_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.btf_id = id;
|
attr.btf_id = id;
|
||||||
|
|
||||||
return sys_bpf(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_link_get_fd_by_id(__u32 id)
|
int bpf_link_get_fd_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.link_id = id;
|
attr.link_id = id;
|
||||||
|
|
||||||
return sys_bpf(BPF_LINK_GET_FD_BY_ID, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_LINK_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
||||||
@@ -881,21 +971,24 @@ int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len)
|
|||||||
attr.info.info = ptr_to_u64(info);
|
attr.info.info = ptr_to_u64(info);
|
||||||
|
|
||||||
err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
|
err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
*info_len = attr.info.info_len;
|
*info_len = attr.info.info_len;
|
||||||
|
|
||||||
return err;
|
return libbpf_err_errno(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.raw_tracepoint.name = ptr_to_u64(name);
|
attr.raw_tracepoint.name = ptr_to_u64(name);
|
||||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||||
|
|
||||||
return sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_load_btf(const void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,
|
int bpf_load_btf(const void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size,
|
||||||
@@ -915,12 +1008,13 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd = sys_bpf(BPF_BTF_LOAD, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_BTF_LOAD, &attr, sizeof(attr));
|
||||||
if (fd == -1 && !do_log && log_buf && log_buf_size) {
|
|
||||||
|
if (fd < 0 && !do_log && log_buf && log_buf_size) {
|
||||||
do_log = true;
|
do_log = true;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
|
int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
|
||||||
@@ -937,37 +1031,42 @@ int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len,
|
|||||||
attr.task_fd_query.buf_len = *buf_len;
|
attr.task_fd_query.buf_len = *buf_len;
|
||||||
|
|
||||||
err = sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr));
|
err = sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr));
|
||||||
|
|
||||||
*buf_len = attr.task_fd_query.buf_len;
|
*buf_len = attr.task_fd_query.buf_len;
|
||||||
*prog_id = attr.task_fd_query.prog_id;
|
*prog_id = attr.task_fd_query.prog_id;
|
||||||
*fd_type = attr.task_fd_query.fd_type;
|
*fd_type = attr.task_fd_query.fd_type;
|
||||||
*probe_offset = attr.task_fd_query.probe_offset;
|
*probe_offset = attr.task_fd_query.probe_offset;
|
||||||
*probe_addr = attr.task_fd_query.probe_addr;
|
*probe_addr = attr.task_fd_query.probe_addr;
|
||||||
|
|
||||||
return err;
|
return libbpf_err_errno(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_enable_stats(enum bpf_stats_type type)
|
int bpf_enable_stats(enum bpf_stats_type type)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.enable_stats.type = type;
|
attr.enable_stats.type = type;
|
||||||
|
|
||||||
return sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_prog_bind_map(int prog_fd, int map_fd,
|
int bpf_prog_bind_map(int prog_fd, int map_fd,
|
||||||
const struct bpf_prog_bind_opts *opts)
|
const struct bpf_prog_bind_opts *opts)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_prog_bind_opts))
|
if (!OPTS_VALID(opts, bpf_prog_bind_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
attr.prog_bind_map.prog_fd = prog_fd;
|
attr.prog_bind_map.prog_fd = prog_fd;
|
||||||
attr.prog_bind_map.map_fd = map_fd;
|
attr.prog_bind_map.map_fd = map_fd;
|
||||||
attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0);
|
attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0);
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr));
|
ret = sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr));
|
||||||
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/bpf.h
10
src/bpf.h
@@ -124,6 +124,8 @@ LIBBPF_API int bpf_map_lookup_elem_flags(int fd, const void *key, void *value,
|
|||||||
__u64 flags);
|
__u64 flags);
|
||||||
LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
|
LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
|
||||||
void *value);
|
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(int fd, const void *key);
|
||||||
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
||||||
LIBBPF_API int bpf_map_freeze(int fd);
|
LIBBPF_API int bpf_map_freeze(int fd);
|
||||||
@@ -175,8 +177,14 @@ struct bpf_link_create_opts {
|
|||||||
union bpf_iter_link_info *iter_info;
|
union bpf_iter_link_info *iter_info;
|
||||||
__u32 iter_info_len;
|
__u32 iter_info_len;
|
||||||
__u32 target_btf_id;
|
__u32 target_btf_id;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
} perf_event;
|
||||||
|
};
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_link_create_opts__last_field target_btf_id
|
#define bpf_link_create_opts__last_field perf_event
|
||||||
|
|
||||||
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
||||||
enum bpf_attach_type attach_type,
|
enum bpf_attach_type attach_type,
|
||||||
|
|||||||
@@ -88,11 +88,19 @@ enum bpf_enum_value_kind {
|
|||||||
const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \
|
||||||
unsigned long long val; \
|
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)) { \
|
switch (__CORE_RELO(s, field, BYTE_SIZE)) { \
|
||||||
case 1: val = *(const unsigned char *)p; \
|
case 1: val = *(const unsigned char *)p; break; \
|
||||||
case 2: val = *(const unsigned short *)p; \
|
case 2: val = *(const unsigned short *)p; break; \
|
||||||
case 4: val = *(const unsigned int *)p; \
|
case 4: val = *(const unsigned int *)p; break; \
|
||||||
case 8: val = *(const unsigned long long *)p; \
|
case 8: val = *(const unsigned long long *)p; break; \
|
||||||
} \
|
} \
|
||||||
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
val <<= __CORE_RELO(s, field, LSHIFT_U64); \
|
||||||
if (__CORE_RELO(s, field, SIGNED)) \
|
if (__CORE_RELO(s, field, SIGNED)) \
|
||||||
@@ -195,17 +203,22 @@ enum bpf_enum_value_kind {
|
|||||||
* (local) BTF, used to record relocation.
|
* (local) BTF, used to record relocation.
|
||||||
*/
|
*/
|
||||||
#define bpf_core_read(dst, sz, src) \
|
#define bpf_core_read(dst, sz, src) \
|
||||||
bpf_probe_read_kernel(dst, sz, \
|
bpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||||
(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()
|
* bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()
|
||||||
* additionally emitting BPF CO-RE field relocation for specified source
|
* additionally emitting BPF CO-RE field relocation for specified source
|
||||||
* argument.
|
* argument.
|
||||||
*/
|
*/
|
||||||
#define bpf_core_read_str(dst, sz, src) \
|
#define bpf_core_read_str(dst, sz, src) \
|
||||||
bpf_probe_read_kernel_str(dst, sz, \
|
bpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src))
|
||||||
(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))
|
||||||
|
|
||||||
#define ___concat(a, b) a ## b
|
#define ___concat(a, b) a ## b
|
||||||
#define ___apply(fn, n) ___concat(fn, n)
|
#define ___apply(fn, n) ___concat(fn, n)
|
||||||
@@ -264,30 +277,29 @@ enum bpf_enum_value_kind {
|
|||||||
read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
|
read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)
|
||||||
|
|
||||||
/* "recursively" read a sequence of inner pointers using local __t var */
|
/* "recursively" read a sequence of inner pointers using local __t var */
|
||||||
#define ___rd_first(src, a) ___read(bpf_core_read, &__t, ___type(src), src, a);
|
#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a);
|
||||||
#define ___rd_last(...) \
|
#define ___rd_last(fn, ...) \
|
||||||
___read(bpf_core_read, &__t, \
|
___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
|
||||||
___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));
|
#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__)
|
||||||
#define ___rd_p1(...) const void *__t; ___rd_first(__VA_ARGS__)
|
#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p2(...) ___rd_p1(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p3(...) ___rd_p2(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p4(...) ___rd_p3(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p5(...) ___rd_p4(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p6(...) ___rd_p5(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p7(...) ___rd_p6(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p8(...) ___rd_p7(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)
|
||||||
#define ___rd_p9(...) ___rd_p8(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__)
|
#define ___read_ptrs(fn, src, ...) \
|
||||||
#define ___read_ptrs(src, ...) \
|
___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__)
|
||||||
___apply(___rd_p, ___narg(__VA_ARGS__))(src, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define ___core_read0(fn, dst, src, a) \
|
#define ___core_read0(fn, fn_ptr, dst, src, a) \
|
||||||
___read(fn, dst, ___type(src), src, a);
|
___read(fn, dst, ___type(src), src, a);
|
||||||
#define ___core_readN(fn, dst, src, ...) \
|
#define ___core_readN(fn, fn_ptr, dst, src, ...) \
|
||||||
___read_ptrs(src, ___nolast(__VA_ARGS__)) \
|
___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__)) \
|
||||||
___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \
|
___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \
|
||||||
___last(__VA_ARGS__));
|
___last(__VA_ARGS__));
|
||||||
#define ___core_read(fn, dst, src, a, ...) \
|
#define ___core_read(fn, fn_ptr, dst, src, a, ...) \
|
||||||
___apply(___core_read, ___empty(__VA_ARGS__))(fn, dst, \
|
___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst, \
|
||||||
src, a, ##__VA_ARGS__)
|
src, a, ##__VA_ARGS__)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -295,20 +307,73 @@ enum bpf_enum_value_kind {
|
|||||||
* BPF_CORE_READ(), in which final field is read into user-provided storage.
|
* BPF_CORE_READ(), in which final field is read into user-provided storage.
|
||||||
* See BPF_CORE_READ() below for more details on general usage.
|
* See BPF_CORE_READ() below for more details on general usage.
|
||||||
*/
|
*/
|
||||||
#define BPF_CORE_READ_INTO(dst, src, a, ...) \
|
#define BPF_CORE_READ_INTO(dst, src, a, ...) ({ \
|
||||||
({ \
|
___core_read(bpf_core_read, bpf_core_read, \
|
||||||
___core_read(bpf_core_read, dst, (src), a, ##__VA_ARGS__) \
|
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__) \
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BPF_CORE_READ_STR_INTO() does same "pointer chasing" as
|
* BPF_CORE_READ_STR_INTO() does same "pointer chasing" as
|
||||||
* BPF_CORE_READ() for intermediate pointers, but then executes (and returns
|
* BPF_CORE_READ() for intermediate pointers, but then executes (and returns
|
||||||
* corresponding error code) bpf_core_read_str() for final string read.
|
* corresponding error code) bpf_core_read_str() for final string read.
|
||||||
*/
|
*/
|
||||||
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \
|
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({ \
|
||||||
({ \
|
___core_read(bpf_core_read_str, bpf_core_read, \
|
||||||
___core_read(bpf_core_read_str, dst, (src), a, ##__VA_ARGS__)\
|
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__) \
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially
|
* BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially
|
||||||
@@ -334,12 +399,46 @@ enum bpf_enum_value_kind {
|
|||||||
* N.B. Only up to 9 "field accessors" are supported, which should be more
|
* N.B. Only up to 9 "field accessors" are supported, which should be more
|
||||||
* than enough for any practical purpose.
|
* than enough for any practical purpose.
|
||||||
*/
|
*/
|
||||||
#define BPF_CORE_READ(src, a, ...) \
|
#define BPF_CORE_READ(src, a, ...) ({ \
|
||||||
({ \
|
___type((src), a, ##__VA_ARGS__) __r; \
|
||||||
___type((src), a, ##__VA_ARGS__) __r; \
|
BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
||||||
BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
|
__r; \
|
||||||
__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; \
|
||||||
|
})
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
41
src/bpf_gen_internal.h
Normal file
41
src/bpf_gen_internal.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
/* Copyright (c) 2021 Facebook */
|
||||||
|
#ifndef __BPF_GEN_INTERNAL_H
|
||||||
|
#define __BPF_GEN_INTERNAL_H
|
||||||
|
|
||||||
|
struct ksym_relo_desc {
|
||||||
|
const char *name;
|
||||||
|
int kind;
|
||||||
|
int insn_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
char attach_target[128];
|
||||||
|
int attach_kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bpf_gen__init(struct bpf_gen *gen, int log_level);
|
||||||
|
int bpf_gen__finish(struct bpf_gen *gen);
|
||||||
|
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, struct bpf_create_map_attr *map_attr, int map_idx);
|
||||||
|
struct bpf_prog_load_params;
|
||||||
|
void bpf_gen__prog_load(struct bpf_gen *gen, struct bpf_prog_load_params *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, int kind, int insn_idx);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* This is auto-generated file. See bpf_helpers_doc.py for details. */
|
/* This is auto-generated file. See bpf_doc.py for details. */
|
||||||
|
|
||||||
/* Forward declarations of BPF structs */
|
/* Forward declarations of BPF structs */
|
||||||
struct bpf_fib_lookup;
|
struct bpf_fib_lookup;
|
||||||
@@ -36,6 +36,7 @@ struct btf_ptr;
|
|||||||
struct inode;
|
struct inode;
|
||||||
struct socket;
|
struct socket;
|
||||||
struct file;
|
struct file;
|
||||||
|
struct bpf_timer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bpf_map_lookup_elem
|
* bpf_map_lookup_elem
|
||||||
@@ -1146,8 +1147,8 @@ static long (*bpf_probe_read_str)(void *dst, __u32 size, const void *unsafe_ptr)
|
|||||||
* identifier that can be assumed unique.
|
* identifier that can be assumed unique.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* A 8-byte long non-decreasing number on success, or 0 if the
|
* A 8-byte long unique number on success, or 0 if the socket
|
||||||
* socket field is missing inside *skb*.
|
* field is missing inside *skb*.
|
||||||
*/
|
*/
|
||||||
static __u64 (*bpf_get_socket_cookie)(void *ctx) = (void *) 46;
|
static __u64 (*bpf_get_socket_cookie)(void *ctx) = (void *) 46;
|
||||||
|
|
||||||
@@ -1249,6 +1250,10 @@ static long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *op
|
|||||||
* Use with ENCAP_L3/L4 flags to further specify the tunnel
|
* Use with ENCAP_L3/L4 flags to further specify the tunnel
|
||||||
* type; *len* is the length of the inner MAC header.
|
* type; *len* is the length of the inner MAC header.
|
||||||
*
|
*
|
||||||
|
* * **BPF_F_ADJ_ROOM_ENCAP_L2_ETH**:
|
||||||
|
* Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the
|
||||||
|
* L2 type as Ethernet.
|
||||||
|
*
|
||||||
* A call to this helper is susceptible to change the underlying
|
* A call to this helper is susceptible to change the underlying
|
||||||
* packet buffer. Therefore, at load time, all checks on pointers
|
* packet buffer. Therefore, at load time, all checks on pointers
|
||||||
* previously done by the verifier are invalidated and must be
|
* previously done by the verifier are invalidated and must be
|
||||||
@@ -1273,8 +1278,12 @@ static long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32
|
|||||||
* The lower two bits of *flags* are used as the return code if
|
* The lower two bits of *flags* are used as the return code if
|
||||||
* the map lookup fails. This is so that the return value can be
|
* the map lookup fails. This is so that the return value can be
|
||||||
* one of the XDP program return codes up to **XDP_TX**, as chosen
|
* one of the XDP program return codes up to **XDP_TX**, as chosen
|
||||||
* by the caller. Any higher bits in the *flags* argument must be
|
* by the caller. The higher bits of *flags* can be set to
|
||||||
* unset.
|
* BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below.
|
||||||
|
*
|
||||||
|
* With BPF_F_BROADCAST the packet will be broadcasted to all the
|
||||||
|
* interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress
|
||||||
|
* interface will be excluded when do broadcasting.
|
||||||
*
|
*
|
||||||
* See also **bpf_redirect**\ (), which only supports redirecting
|
* See also **bpf_redirect**\ (), which only supports redirecting
|
||||||
* to an ifindex, but doesn't require a map to do so.
|
* to an ifindex, but doesn't require a map to do so.
|
||||||
@@ -1799,6 +1808,9 @@ static long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *
|
|||||||
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
||||||
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
||||||
* packet is not forwarded or needs assist from full stack
|
* packet is not forwarded or needs assist from full stack
|
||||||
|
*
|
||||||
|
* If lookup fails with BPF_FIB_LKUP_RET_FRAG_NEEDED, then the MTU
|
||||||
|
* was exceeded and output params->mtu_result contains the MTU.
|
||||||
*/
|
*/
|
||||||
static long (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, int plen, __u32 flags) = (void *) 69;
|
static long (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, int plen, __u32 flags) = (void *) 69;
|
||||||
|
|
||||||
@@ -2071,7 +2083,7 @@ static __u64 (*bpf_get_current_cgroup_id)(void) = (void *) 80;
|
|||||||
* running simultaneously.
|
* running simultaneously.
|
||||||
*
|
*
|
||||||
* A user should care about the synchronization by himself.
|
* A user should care about the synchronization by himself.
|
||||||
* For example, by using the **BPF_STX_XADD** instruction to alter
|
* For example, by using the **BPF_ATOMIC** instructions to alter
|
||||||
* the shared data.
|
* the shared data.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
@@ -2083,7 +2095,7 @@ static void *(*bpf_get_local_storage)(void *map, __u64 flags) = (void *) 81;
|
|||||||
* bpf_sk_select_reuseport
|
* bpf_sk_select_reuseport
|
||||||
*
|
*
|
||||||
* Select a **SO_REUSEPORT** socket from a
|
* Select a **SO_REUSEPORT** socket from a
|
||||||
* **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*.
|
* **BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*.
|
||||||
* It checks the selected socket is matching the incoming
|
* It checks the selected socket is matching the incoming
|
||||||
* request in the socket buffer.
|
* request in the socket buffer.
|
||||||
*
|
*
|
||||||
@@ -2748,10 +2760,10 @@ static long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_p
|
|||||||
* string length is larger than *size*, just *size*-1 bytes are
|
* string length is larger than *size*, just *size*-1 bytes are
|
||||||
* copied and the last byte is set to NUL.
|
* copied and the last byte is set to NUL.
|
||||||
*
|
*
|
||||||
* On success, the length of the copied string is returned. This
|
* On success, returns the number of bytes that were written,
|
||||||
* makes this helper useful in tracing programs for reading
|
* including the terminal NUL. This makes this helper useful in
|
||||||
* strings, and more importantly to get its length at runtime. See
|
* tracing programs for reading strings, and more importantly to
|
||||||
* the following snippet:
|
* get its length at runtime. See the following snippet:
|
||||||
*
|
*
|
||||||
* ::
|
* ::
|
||||||
*
|
*
|
||||||
@@ -2780,7 +2792,7 @@ static long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_p
|
|||||||
* one can quickly iterate at the right offset of the memory area.
|
* one can quickly iterate at the right offset of the memory area.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* On success, the strictly positive length of the string,
|
* On success, the strictly positive length of the output string,
|
||||||
* including the trailing NUL character. On error, a negative
|
* including the trailing NUL character. On error, a negative
|
||||||
* value.
|
* value.
|
||||||
*/
|
*/
|
||||||
@@ -3085,6 +3097,13 @@ static __u64 (*bpf_sk_ancestor_cgroup_id)(void *sk, int ancestor_level) = (void
|
|||||||
* of new data availability is sent.
|
* of new data availability is sent.
|
||||||
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
||||||
* of new data availability is sent unconditionally.
|
* of new data availability is sent unconditionally.
|
||||||
|
* If **0** is specified in *flags*, an adaptive notification
|
||||||
|
* of new data availability is sent.
|
||||||
|
*
|
||||||
|
* An adaptive notification is a notification sent whenever the user-space
|
||||||
|
* process has caught up and consumed all available payloads. In case the user-space
|
||||||
|
* process is still processing a previous payload, then no notification is needed
|
||||||
|
* as it will process the newly added payload automatically.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
@@ -3095,6 +3114,7 @@ static long (*bpf_ringbuf_output)(void *ringbuf, void *data, __u64 size, __u64 f
|
|||||||
* bpf_ringbuf_reserve
|
* bpf_ringbuf_reserve
|
||||||
*
|
*
|
||||||
* Reserve *size* bytes of payload in a ring buffer *ringbuf*.
|
* Reserve *size* bytes of payload in a ring buffer *ringbuf*.
|
||||||
|
* *flags* must be 0.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* Valid pointer with *size* bytes of memory available; NULL,
|
* Valid pointer with *size* bytes of memory available; NULL,
|
||||||
@@ -3110,6 +3130,10 @@ static void *(*bpf_ringbuf_reserve)(void *ringbuf, __u64 size, __u64 flags) = (v
|
|||||||
* of new data availability is sent.
|
* of new data availability is sent.
|
||||||
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
||||||
* of new data availability is sent unconditionally.
|
* of new data availability is sent unconditionally.
|
||||||
|
* If **0** is specified in *flags*, an adaptive notification
|
||||||
|
* of new data availability is sent.
|
||||||
|
*
|
||||||
|
* See 'bpf_ringbuf_output()' for the definition of adaptive notification.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* Nothing. Always succeeds.
|
* Nothing. Always succeeds.
|
||||||
@@ -3124,6 +3148,10 @@ static void (*bpf_ringbuf_submit)(void *data, __u64 flags) = (void *) 132;
|
|||||||
* of new data availability is sent.
|
* of new data availability is sent.
|
||||||
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
* If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification
|
||||||
* of new data availability is sent unconditionally.
|
* of new data availability is sent unconditionally.
|
||||||
|
* If **0** is specified in *flags*, an adaptive notification
|
||||||
|
* of new data availability is sent.
|
||||||
|
*
|
||||||
|
* See 'bpf_ringbuf_output()' for the definition of adaptive notification.
|
||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
* Nothing. Always succeeds.
|
* Nothing. Always succeeds.
|
||||||
@@ -3731,4 +3759,278 @@ static long (*bpf_ima_inode_hash)(struct inode *inode, void *dst, __u32 size) =
|
|||||||
*/
|
*/
|
||||||
static struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162;
|
static struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_check_mtu
|
||||||
|
*
|
||||||
|
* Check packet size against exceeding MTU of net device (based
|
||||||
|
* on *ifindex*). This helper will likely be used in combination
|
||||||
|
* with helpers that adjust/change the packet size.
|
||||||
|
*
|
||||||
|
* The argument *len_diff* can be used for querying with a planned
|
||||||
|
* size change. This allows to check MTU prior to changing packet
|
||||||
|
* ctx. Providing an *len_diff* adjustment that is larger than the
|
||||||
|
* actual packet size (resulting in negative packet size) will in
|
||||||
|
* principle not exceed the MTU, why it is not considered a
|
||||||
|
* failure. Other BPF-helpers are needed for performing the
|
||||||
|
* planned size change, why the responsability for catch a negative
|
||||||
|
* packet size belong in those helpers.
|
||||||
|
*
|
||||||
|
* Specifying *ifindex* zero means the MTU check is performed
|
||||||
|
* against the current net device. This is practical if this isn't
|
||||||
|
* used prior to redirect.
|
||||||
|
*
|
||||||
|
* On input *mtu_len* must be a valid pointer, else verifier will
|
||||||
|
* reject BPF program. If the value *mtu_len* is initialized to
|
||||||
|
* zero then the ctx packet size is use. When value *mtu_len* is
|
||||||
|
* provided as input this specify the L3 length that the MTU check
|
||||||
|
* is done against. Remember XDP and TC length operate at L2, but
|
||||||
|
* this value is L3 as this correlate to MTU and IP-header tot_len
|
||||||
|
* values which are L3 (similar behavior as bpf_fib_lookup).
|
||||||
|
*
|
||||||
|
* The Linux kernel route table can configure MTUs on a more
|
||||||
|
* specific per route level, which is not provided by this helper.
|
||||||
|
* For route level MTU checks use the **bpf_fib_lookup**\ ()
|
||||||
|
* helper.
|
||||||
|
*
|
||||||
|
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||||
|
* **struct sk_buff** for tc cls_act programs.
|
||||||
|
*
|
||||||
|
* The *flags* argument can be a combination of one or more of the
|
||||||
|
* following values:
|
||||||
|
*
|
||||||
|
* **BPF_MTU_CHK_SEGS**
|
||||||
|
* This flag will only works for *ctx* **struct sk_buff**.
|
||||||
|
* If packet context contains extra packet segment buffers
|
||||||
|
* (often knows as GSO skb), then MTU check is harder to
|
||||||
|
* check at this point, because in transmit path it is
|
||||||
|
* possible for the skb packet to get re-segmented
|
||||||
|
* (depending on net device features). This could still be
|
||||||
|
* a MTU violation, so this flag enables performing MTU
|
||||||
|
* check against segments, with a different violation
|
||||||
|
* return code to tell it apart. Check cannot use len_diff.
|
||||||
|
*
|
||||||
|
* On return *mtu_len* pointer contains the MTU value of the net
|
||||||
|
* device. Remember the net device configured MTU is the L3 size,
|
||||||
|
* which is returned here and XDP and TC length operate at L2.
|
||||||
|
* Helper take this into account for you, but remember when using
|
||||||
|
* MTU value in your BPF-code.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* * 0 on success, and populate MTU value in *mtu_len* pointer.
|
||||||
|
*
|
||||||
|
* * < 0 if any input argument is invalid (*mtu_len* not updated)
|
||||||
|
*
|
||||||
|
* MTU violations return positive values, but also populate MTU
|
||||||
|
* value in *mtu_len* pointer, as this can be needed for
|
||||||
|
* implementing PMTU handing:
|
||||||
|
*
|
||||||
|
* * **BPF_MTU_CHK_RET_FRAG_NEEDED**
|
||||||
|
* * **BPF_MTU_CHK_RET_SEGS_TOOBIG**
|
||||||
|
*/
|
||||||
|
static long (*bpf_check_mtu)(void *ctx, __u32 ifindex, __u32 *mtu_len, __s32 len_diff, __u64 flags) = (void *) 163;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_for_each_map_elem
|
||||||
|
*
|
||||||
|
* For each element in **map**, call **callback_fn** function with
|
||||||
|
* **map**, **callback_ctx** and other map-specific parameters.
|
||||||
|
* The **callback_fn** should be a static function and
|
||||||
|
* the **callback_ctx** should be a pointer to the stack.
|
||||||
|
* The **flags** is used to control certain aspects of the helper.
|
||||||
|
* Currently, the **flags** must be 0.
|
||||||
|
*
|
||||||
|
* The following are a list of supported map types and their
|
||||||
|
* respective expected callback signatures:
|
||||||
|
*
|
||||||
|
* BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH,
|
||||||
|
* BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH,
|
||||||
|
* BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY
|
||||||
|
*
|
||||||
|
* long (\*callback_fn)(struct bpf_map \*map, const void \*key, void \*value, void \*ctx);
|
||||||
|
*
|
||||||
|
* For per_cpu maps, the map_value is the value on the cpu where the
|
||||||
|
* bpf_prog is running.
|
||||||
|
*
|
||||||
|
* If **callback_fn** return 0, the helper will continue to the next
|
||||||
|
* element. If return value is 1, the helper will skip the rest of
|
||||||
|
* elements and return. Other return values are not used now.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* The number of traversed map elements for success, **-EINVAL** for
|
||||||
|
* invalid **flags**.
|
||||||
|
*/
|
||||||
|
static long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 164;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_snprintf
|
||||||
|
*
|
||||||
|
* Outputs a string into the **str** buffer of size **str_size**
|
||||||
|
* based on a format string stored in a read-only map pointed by
|
||||||
|
* **fmt**.
|
||||||
|
*
|
||||||
|
* Each format specifier in **fmt** corresponds to one u64 element
|
||||||
|
* in the **data** array. For strings and pointers where pointees
|
||||||
|
* are accessed, only the pointer values are stored in the *data*
|
||||||
|
* array. The *data_len* is the size of *data* in bytes.
|
||||||
|
*
|
||||||
|
* Formats **%s** and **%p{i,I}{4,6}** require to read kernel
|
||||||
|
* memory. Reading kernel memory may fail due to either invalid
|
||||||
|
* address or valid address but requiring a major memory fault. If
|
||||||
|
* reading kernel memory fails, the string for **%s** will be an
|
||||||
|
* empty string, and the ip address for **%p{i,I}{4,6}** will be 0.
|
||||||
|
* Not returning error to bpf program is consistent with what
|
||||||
|
* **bpf_trace_printk**\ () does for now.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* The strictly positive length of the formatted string, including
|
||||||
|
* the trailing zero character. If the return value is greater than
|
||||||
|
* **str_size**, **str** contains a truncated string, guaranteed to
|
||||||
|
* be zero-terminated except when **str_size** is 0.
|
||||||
|
*
|
||||||
|
* Or **-EBUSY** if the per-CPU memory copy buffer is busy.
|
||||||
|
*/
|
||||||
|
static long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_sys_bpf
|
||||||
|
*
|
||||||
|
* Execute bpf syscall with given arguments.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* A syscall result.
|
||||||
|
*/
|
||||||
|
static long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = (void *) 166;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_btf_find_by_name_kind
|
||||||
|
*
|
||||||
|
* Find BTF type with given name and kind in vmlinux BTF or in module's BTFs.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* Returns btf_id and btf_obj_fd in lower and upper 32 bits.
|
||||||
|
*/
|
||||||
|
static long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = (void *) 167;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_sys_close
|
||||||
|
*
|
||||||
|
* Execute close syscall for given FD.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* A syscall result.
|
||||||
|
*/
|
||||||
|
static long (*bpf_sys_close)(__u32 fd) = (void *) 168;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_timer_init
|
||||||
|
*
|
||||||
|
* Initialize the timer.
|
||||||
|
* First 4 bits of *flags* specify clockid.
|
||||||
|
* Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed.
|
||||||
|
* All other bits of *flags* are reserved.
|
||||||
|
* The verifier will reject the program if *timer* is not from
|
||||||
|
* the same *map*.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 on success.
|
||||||
|
* **-EBUSY** if *timer* is already initialized.
|
||||||
|
* **-EINVAL** if invalid *flags* are passed.
|
||||||
|
* **-EPERM** if *timer* is in a map that doesn't have any user references.
|
||||||
|
* The user space should either hold a file descriptor to a map with timers
|
||||||
|
* or pin such map in bpffs. When map is unpinned or file descriptor is
|
||||||
|
* closed all timers in the map will be cancelled and freed.
|
||||||
|
*/
|
||||||
|
static long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = (void *) 169;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_timer_set_callback
|
||||||
|
*
|
||||||
|
* Configure the timer to call *callback_fn* static function.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 on success.
|
||||||
|
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
|
||||||
|
* **-EPERM** if *timer* is in a map that doesn't have any user references.
|
||||||
|
* The user space should either hold a file descriptor to a map with timers
|
||||||
|
* or pin such map in bpffs. When map is unpinned or file descriptor is
|
||||||
|
* closed all timers in the map will be cancelled and freed.
|
||||||
|
*/
|
||||||
|
static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = (void *) 170;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_timer_start
|
||||||
|
*
|
||||||
|
* Set timer expiration N nanoseconds from the current time. The
|
||||||
|
* configured callback will be invoked in soft irq context on some cpu
|
||||||
|
* and will not repeat unless another bpf_timer_start() is made.
|
||||||
|
* In such case the next invocation can migrate to a different cpu.
|
||||||
|
* Since struct bpf_timer is a field inside map element the map
|
||||||
|
* owns the timer. The bpf_timer_set_callback() will increment refcnt
|
||||||
|
* of BPF program to make sure that callback_fn code stays valid.
|
||||||
|
* When user space reference to a map reaches zero all timers
|
||||||
|
* in a map are cancelled and corresponding program's refcnts are
|
||||||
|
* decremented. This is done to make sure that Ctrl-C of a user
|
||||||
|
* process doesn't leave any timers running. If map is pinned in
|
||||||
|
* bpffs the callback_fn can re-arm itself indefinitely.
|
||||||
|
* bpf_map_update/delete_elem() helpers and user space sys_bpf commands
|
||||||
|
* cancel and free the timer in the given map element.
|
||||||
|
* The map can contain timers that invoke callback_fn-s from different
|
||||||
|
* programs. The same callback_fn can serve different timers from
|
||||||
|
* different maps if key/value layout matches across maps.
|
||||||
|
* Every bpf_timer_set_callback() can have different callback_fn.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 on success.
|
||||||
|
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier
|
||||||
|
* or invalid *flags* are passed.
|
||||||
|
*/
|
||||||
|
static long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = (void *) 171;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_timer_cancel
|
||||||
|
*
|
||||||
|
* Cancel the timer and wait for callback_fn to finish if it was running.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 if the timer was not active.
|
||||||
|
* 1 if the timer was active.
|
||||||
|
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
|
||||||
|
* **-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its
|
||||||
|
* own timer which would have led to a deadlock otherwise.
|
||||||
|
*/
|
||||||
|
static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_get_func_ip
|
||||||
|
*
|
||||||
|
* Get address of the traced function (for tracing and kprobe programs).
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* Address of the traced function.
|
||||||
|
*/
|
||||||
|
static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_get_attach_cookie
|
||||||
|
*
|
||||||
|
* Get bpf_cookie value provided (optionally) during the program
|
||||||
|
* attachment. It might be different for each individual
|
||||||
|
* attachment, even if BPF program itself is the same.
|
||||||
|
* Expects BPF program context *ctx* as a first argument.
|
||||||
|
*
|
||||||
|
* Supported for the following program types:
|
||||||
|
* - kprobe/uprobe;
|
||||||
|
* - tracepoint;
|
||||||
|
* - perf_event.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* Value specified by user at BPF link creation/attachment time
|
||||||
|
* or 0, if it was not specified.
|
||||||
|
*/
|
||||||
|
static __u64 (*bpf_get_attach_cookie)(void *ctx) = (void *) 174;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,21 @@
|
|||||||
/*
|
/*
|
||||||
* Helper macro to place programs, maps, license in
|
* Helper macro to place programs, maps, license in
|
||||||
* different sections in elf_bpf file. Section names
|
* different sections in elf_bpf file. Section names
|
||||||
* are interpreted by elf_bpf loader
|
* 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.
|
||||||
*/
|
*/
|
||||||
#define SEC(NAME) __attribute__((section(NAME), used))
|
#define SEC(name) \
|
||||||
|
_Pragma("GCC diagnostic push") \
|
||||||
|
_Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \
|
||||||
|
__attribute__((section(name), used)) \
|
||||||
|
_Pragma("GCC diagnostic pop") \
|
||||||
|
|
||||||
|
/* Avoid 'linux/stddef.h' definition of '__always_inline'. */
|
||||||
|
#undef __always_inline
|
||||||
|
#define __always_inline inline __attribute__((always_inline))
|
||||||
|
|
||||||
#ifndef __always_inline
|
|
||||||
#define __always_inline __attribute__((always_inline))
|
|
||||||
#endif
|
|
||||||
#ifndef __noinline
|
#ifndef __noinline
|
||||||
#define __noinline __attribute__((noinline))
|
#define __noinline __attribute__((noinline))
|
||||||
#endif
|
#endif
|
||||||
@@ -40,7 +48,29 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper macro to manipulate data structures
|
* 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
|
||||||
*/
|
*/
|
||||||
#ifndef offsetof
|
#ifndef offsetof
|
||||||
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
|
||||||
@@ -128,4 +158,70 @@ enum libbpf_tristate {
|
|||||||
#define __kconfig __attribute__((section(".kconfig")))
|
#define __kconfig __attribute__((section(".kconfig")))
|
||||||
#define __ksym __attribute__((section(".ksyms")))
|
#define __ksym __attribute__((section(".ksyms")))
|
||||||
|
|
||||||
|
#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)); \
|
||||||
|
})
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
nr_linfo = info->nr_line_info;
|
nr_linfo = info->nr_line_info;
|
||||||
|
|
||||||
if (!nr_linfo)
|
if (!nr_linfo)
|
||||||
return NULL;
|
return errno = EINVAL, NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The min size that bpf_prog_linfo has to access for
|
* The min size that bpf_prog_linfo has to access for
|
||||||
@@ -114,11 +114,11 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
*/
|
*/
|
||||||
if (info->line_info_rec_size <
|
if (info->line_info_rec_size <
|
||||||
offsetof(struct bpf_line_info, file_name_off))
|
offsetof(struct bpf_line_info, file_name_off))
|
||||||
return NULL;
|
return errno = EINVAL, NULL;
|
||||||
|
|
||||||
prog_linfo = calloc(1, sizeof(*prog_linfo));
|
prog_linfo = calloc(1, sizeof(*prog_linfo));
|
||||||
if (!prog_linfo)
|
if (!prog_linfo)
|
||||||
return NULL;
|
return errno = ENOMEM, NULL;
|
||||||
|
|
||||||
/* Copy xlated line_info */
|
/* Copy xlated line_info */
|
||||||
prog_linfo->nr_linfo = nr_linfo;
|
prog_linfo->nr_linfo = nr_linfo;
|
||||||
@@ -174,7 +174,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
|||||||
|
|
||||||
err_free:
|
err_free:
|
||||||
bpf_prog_linfo__free(prog_linfo);
|
bpf_prog_linfo__free(prog_linfo);
|
||||||
return NULL;
|
return errno = EINVAL, NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct bpf_line_info *
|
const struct bpf_line_info *
|
||||||
@@ -186,11 +186,11 @@ bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
|||||||
const __u64 *jited_linfo;
|
const __u64 *jited_linfo;
|
||||||
|
|
||||||
if (func_idx >= prog_linfo->nr_jited_func)
|
if (func_idx >= prog_linfo->nr_jited_func)
|
||||||
return NULL;
|
return errno = ENOENT, NULL;
|
||||||
|
|
||||||
nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
|
nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
|
||||||
if (nr_skip >= nr_linfo)
|
if (nr_skip >= nr_linfo)
|
||||||
return NULL;
|
return errno = ENOENT, NULL;
|
||||||
|
|
||||||
start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
|
start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
|
||||||
jited_rec_size = prog_linfo->jited_rec_size;
|
jited_rec_size = prog_linfo->jited_rec_size;
|
||||||
@@ -198,7 +198,7 @@ bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
|||||||
(start * jited_rec_size);
|
(start * jited_rec_size);
|
||||||
jited_linfo = raw_jited_linfo;
|
jited_linfo = raw_jited_linfo;
|
||||||
if (addr < *jited_linfo)
|
if (addr < *jited_linfo)
|
||||||
return NULL;
|
return errno = ENOENT, NULL;
|
||||||
|
|
||||||
nr_linfo -= nr_skip;
|
nr_linfo -= nr_skip;
|
||||||
rec_size = prog_linfo->rec_size;
|
rec_size = prog_linfo->rec_size;
|
||||||
@@ -225,13 +225,13 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
|
|||||||
|
|
||||||
nr_linfo = prog_linfo->nr_linfo;
|
nr_linfo = prog_linfo->nr_linfo;
|
||||||
if (nr_skip >= nr_linfo)
|
if (nr_skip >= nr_linfo)
|
||||||
return NULL;
|
return errno = ENOENT, NULL;
|
||||||
|
|
||||||
rec_size = prog_linfo->rec_size;
|
rec_size = prog_linfo->rec_size;
|
||||||
raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
|
raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
|
||||||
linfo = raw_linfo;
|
linfo = raw_linfo;
|
||||||
if (insn_off < linfo->insn_off)
|
if (insn_off < linfo->insn_off)
|
||||||
return NULL;
|
return errno = ENOENT, NULL;
|
||||||
|
|
||||||
nr_linfo -= nr_skip;
|
nr_linfo -= nr_skip;
|
||||||
for (i = 0; i < nr_linfo; i++) {
|
for (i = 0; i < nr_linfo; i++) {
|
||||||
|
|||||||
@@ -25,26 +25,35 @@
|
|||||||
#define bpf_target_sparc
|
#define bpf_target_sparc
|
||||||
#define bpf_target_defined
|
#define bpf_target_defined
|
||||||
#else
|
#else
|
||||||
#undef bpf_target_defined
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fall back to what the compiler says */
|
/* Fall back to what the compiler says */
|
||||||
#ifndef bpf_target_defined
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
#define bpf_target_x86
|
#define bpf_target_x86
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__s390__)
|
#elif defined(__s390__)
|
||||||
#define bpf_target_s390
|
#define bpf_target_s390
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
#define bpf_target_arm
|
#define bpf_target_arm
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define bpf_target_arm64
|
#define bpf_target_arm64
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
#define bpf_target_mips
|
#define bpf_target_mips
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__powerpc__)
|
#elif defined(__powerpc__)
|
||||||
#define bpf_target_powerpc
|
#define bpf_target_powerpc
|
||||||
|
#define bpf_target_defined
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
#define bpf_target_sparc
|
#define bpf_target_sparc
|
||||||
|
#define bpf_target_defined
|
||||||
|
#endif /* no compiler target */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __BPF_TARGET_MISSING
|
||||||
|
#define __BPF_TARGET_MISSING "GCC error \"Must specify a BPF target arch via __TARGET_ARCH_xxx\""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(bpf_target_x86)
|
#if defined(bpf_target_x86)
|
||||||
@@ -287,7 +296,7 @@ struct pt_regs;
|
|||||||
#elif defined(bpf_target_sparc)
|
#elif defined(bpf_target_sparc)
|
||||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); })
|
#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); })
|
||||||
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
|
||||||
#else
|
#elif defined(bpf_target_defined)
|
||||||
#define BPF_KPROBE_READ_RET_IP(ip, ctx) \
|
#define BPF_KPROBE_READ_RET_IP(ip, ctx) \
|
||||||
({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
|
||||||
#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \
|
#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \
|
||||||
@@ -295,13 +304,48 @@ struct pt_regs;
|
|||||||
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !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; })
|
||||||
|
|
||||||
|
#endif /* !defined(bpf_target_defined) */
|
||||||
|
|
||||||
|
#ifndef ___bpf_concat
|
||||||
#define ___bpf_concat(a, b) a ## b
|
#define ___bpf_concat(a, b) a ## b
|
||||||
|
#endif
|
||||||
|
#ifndef ___bpf_apply
|
||||||
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
|
#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
|
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
|
||||||
|
#endif
|
||||||
|
#ifndef ___bpf_narg
|
||||||
#define ___bpf_narg(...) \
|
#define ___bpf_narg(...) \
|
||||||
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
#define ___bpf_empty(...) \
|
#endif
|
||||||
___bpf_nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)
|
|
||||||
|
|
||||||
#define ___bpf_ctx_cast0() ctx
|
#define ___bpf_ctx_cast0() ctx
|
||||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
||||||
@@ -413,20 +457,4 @@ typeof(name(0)) name(struct pt_regs *ctx) \
|
|||||||
} \
|
} \
|
||||||
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
||||||
|
|
||||||
/*
|
|
||||||
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
|
|
||||||
* in a structure.
|
|
||||||
*/
|
|
||||||
#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
|
#endif
|
||||||
|
|||||||
40
src/btf.h
40
src/btf.h
@@ -44,8 +44,17 @@ LIBBPF_API struct btf *btf__parse_elf_split(const char *path, struct btf *base_b
|
|||||||
LIBBPF_API struct btf *btf__parse_raw(const char *path);
|
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__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_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||||
|
|
||||||
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
||||||
LIBBPF_API int btf__load(struct btf *btf);
|
LIBBPF_API int btf__load(struct btf *btf);
|
||||||
|
LIBBPF_API int btf__load_into_kernel(struct btf *btf);
|
||||||
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
||||||
const char *type_name);
|
const char *type_name);
|
||||||
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
|
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
|
||||||
@@ -66,7 +75,6 @@ LIBBPF_API void btf__set_fd(struct btf *btf, int fd);
|
|||||||
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||||
LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);
|
LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);
|
||||||
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,
|
LIBBPF_API int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
||||||
__u32 expected_key_size,
|
__u32 expected_key_size,
|
||||||
__u32 expected_value_size,
|
__u32 expected_value_size,
|
||||||
@@ -89,12 +97,13 @@ int btf_ext__reloc_line_info(const struct btf *btf,
|
|||||||
LIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
LIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
LIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
LIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
|
|
||||||
LIBBPF_API struct btf *libbpf_find_kernel_btf(void);
|
|
||||||
|
|
||||||
LIBBPF_API int btf__find_str(struct btf *btf, const char *s);
|
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_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);
|
||||||
|
|
||||||
LIBBPF_API int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding);
|
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_ptr(struct btf *btf, int ref_type_id);
|
||||||
LIBBPF_API int btf__add_array(struct btf *btf,
|
LIBBPF_API int btf__add_array(struct btf *btf,
|
||||||
int index_type_id, int elem_type_id, __u32 nr_elems);
|
int index_type_id, int elem_type_id, __u32 nr_elems);
|
||||||
@@ -173,6 +182,7 @@ struct btf_dump_emit_type_decl_opts {
|
|||||||
int indent_level;
|
int indent_level;
|
||||||
/* strip all the const/volatile/restrict mods */
|
/* strip all the const/volatile/restrict mods */
|
||||||
bool strip_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 strip_mods
|
||||||
|
|
||||||
@@ -180,6 +190,25 @@ LIBBPF_API int
|
|||||||
btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
||||||
const struct btf_dump_emit_type_decl_opts *opts);
|
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
|
* A set of helpers for easier BTF types handling
|
||||||
*/
|
*/
|
||||||
@@ -294,6 +323,11 @@ static inline bool btf_is_datasec(const struct btf_type *t)
|
|||||||
return btf_kind(t) == BTF_KIND_DATASEC;
|
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 __u8 btf_int_encoding(const struct btf_type *t)
|
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||||
{
|
{
|
||||||
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
||||||
|
|||||||
899
src/btf_dump.c
899
src/btf_dump.c
File diff suppressed because it is too large
Load Diff
729
src/gen_loader.c
Normal file
729
src/gen_loader.c
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
/* Copyright (c) 2021 Facebook */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include "btf.h"
|
||||||
|
#include "bpf.h"
|
||||||
|
#include "libbpf.h"
|
||||||
|
#include "libbpf_internal.h"
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include "bpf_gen_internal.h"
|
||||||
|
#include "skel_internal.h"
|
||||||
|
|
||||||
|
#define MAX_USED_MAPS 64
|
||||||
|
#define MAX_USED_PROGS 32
|
||||||
|
|
||||||
|
/* The following structure describes the stack layout of the loader program.
|
||||||
|
* In addition R6 contains the pointer to context.
|
||||||
|
* R7 contains the result of the last sys_bpf command (typically error or FD).
|
||||||
|
* R9 contains the result of the last sys_close command.
|
||||||
|
*
|
||||||
|
* Naming convention:
|
||||||
|
* ctx - bpf program context
|
||||||
|
* stack - bpf program stack
|
||||||
|
* blob - bpf_attr-s, strings, insns, map data.
|
||||||
|
* All the bytes that loader prog will use for read/write.
|
||||||
|
*/
|
||||||
|
struct loader_stack {
|
||||||
|
__u32 btf_fd;
|
||||||
|
__u32 map_fd[MAX_USED_MAPS];
|
||||||
|
__u32 prog_fd[MAX_USED_PROGS];
|
||||||
|
__u32 inner_map_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define stack_off(field) \
|
||||||
|
(__s16)(-sizeof(struct loader_stack) + offsetof(struct loader_stack, field))
|
||||||
|
|
||||||
|
#define attr_field(attr, field) (attr + offsetof(union bpf_attr, field))
|
||||||
|
|
||||||
|
static int realloc_insn_buf(struct bpf_gen *gen, __u32 size)
|
||||||
|
{
|
||||||
|
size_t off = gen->insn_cur - gen->insn_start;
|
||||||
|
void *insn_start;
|
||||||
|
|
||||||
|
if (gen->error)
|
||||||
|
return gen->error;
|
||||||
|
if (size > INT32_MAX || off + size > INT32_MAX) {
|
||||||
|
gen->error = -ERANGE;
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
insn_start = realloc(gen->insn_start, off + size);
|
||||||
|
if (!insn_start) {
|
||||||
|
gen->error = -ENOMEM;
|
||||||
|
free(gen->insn_start);
|
||||||
|
gen->insn_start = NULL;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
gen->insn_start = insn_start;
|
||||||
|
gen->insn_cur = insn_start + off;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int realloc_data_buf(struct bpf_gen *gen, __u32 size)
|
||||||
|
{
|
||||||
|
size_t off = gen->data_cur - gen->data_start;
|
||||||
|
void *data_start;
|
||||||
|
|
||||||
|
if (gen->error)
|
||||||
|
return gen->error;
|
||||||
|
if (size > INT32_MAX || off + size > INT32_MAX) {
|
||||||
|
gen->error = -ERANGE;
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
data_start = realloc(gen->data_start, off + size);
|
||||||
|
if (!data_start) {
|
||||||
|
gen->error = -ENOMEM;
|
||||||
|
free(gen->data_start);
|
||||||
|
gen->data_start = NULL;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
gen->data_start = data_start;
|
||||||
|
gen->data_cur = data_start + off;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit(struct bpf_gen *gen, struct bpf_insn insn)
|
||||||
|
{
|
||||||
|
if (realloc_insn_buf(gen, sizeof(insn)))
|
||||||
|
return;
|
||||||
|
memcpy(gen->insn_cur, &insn, sizeof(insn));
|
||||||
|
gen->insn_cur += sizeof(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn insn2)
|
||||||
|
{
|
||||||
|
emit(gen, insn1);
|
||||||
|
emit(gen, insn2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__init(struct bpf_gen *gen, int log_level)
|
||||||
|
{
|
||||||
|
size_t stack_sz = sizeof(struct loader_stack);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gen->log_level = log_level;
|
||||||
|
/* save ctx pointer into R6 */
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
|
||||||
|
|
||||||
|
/* bzero stack */
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
|
||||||
|
emit(gen, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -stack_sz));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_2, stack_sz));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
|
||||||
|
|
||||||
|
/* jump over cleanup code */
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0,
|
||||||
|
/* size of cleanup code below */
|
||||||
|
(stack_sz / 4) * 3 + 2));
|
||||||
|
|
||||||
|
/* remember the label where all error branches will jump to */
|
||||||
|
gen->cleanup_label = gen->insn_cur - gen->insn_start;
|
||||||
|
/* emit cleanup code: close all temp FDs */
|
||||||
|
for (i = 0; i < stack_sz; i += 4) {
|
||||||
|
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -stack_sz + i));
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0, 1));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
|
||||||
|
}
|
||||||
|
/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
|
||||||
|
emit(gen, BPF_EXIT_INSN());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
|
||||||
|
{
|
||||||
|
void *prev;
|
||||||
|
|
||||||
|
if (realloc_data_buf(gen, size))
|
||||||
|
return 0;
|
||||||
|
prev = gen->data_cur;
|
||||||
|
memcpy(gen->data_cur, data, size);
|
||||||
|
gen->data_cur += size;
|
||||||
|
return prev - gen->data_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int insn_bytes_to_bpf_size(__u32 sz)
|
||||||
|
{
|
||||||
|
switch (sz) {
|
||||||
|
case 8: return BPF_DW;
|
||||||
|
case 4: return BPF_W;
|
||||||
|
case 2: return BPF_H;
|
||||||
|
case 1: return BPF_B;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *(u64 *)(blob + off) = (u64)(void *)(blob + data) */
|
||||||
|
static void emit_rel_store(struct bpf_gen *gen, int off, int data)
|
||||||
|
{
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, data));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, off));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *(u64 *)(blob + off) = (u64)(void *)(%sp + stack_off) */
|
||||||
|
static void emit_rel_store_sp(struct bpf_gen *gen, int off, int stack_off)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_10));
|
||||||
|
emit(gen, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, stack_off));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, off));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void move_ctx2blob(struct bpf_gen *gen, int off, int size, int ctx_off,
|
||||||
|
bool check_non_zero)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_6, ctx_off));
|
||||||
|
if (check_non_zero)
|
||||||
|
/* If value in ctx is zero don't update the blob.
|
||||||
|
* For example: when ctx->map.max_entries == 0, keep default max_entries from bpf.c
|
||||||
|
*/
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, off));
|
||||||
|
emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_1, BPF_REG_0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void move_stack2blob(struct bpf_gen *gen, int off, int size, int stack_off)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_10, stack_off));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, off));
|
||||||
|
emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_1, BPF_REG_0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void move_stack2ctx(struct bpf_gen *gen, int ctx_off, int size, int stack_off)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_LDX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_0, BPF_REG_10, stack_off));
|
||||||
|
emit(gen, BPF_STX_MEM(insn_bytes_to_bpf_size(size), BPF_REG_6, BPF_REG_0, ctx_off));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_sys_bpf(struct bpf_gen *gen, int cmd, int attr, int attr_size)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_1, cmd));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_2, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, attr));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_3, attr_size));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_bpf));
|
||||||
|
/* remember the result in R7 */
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_simm16(__s64 value)
|
||||||
|
{
|
||||||
|
return value == (__s64)(__s16)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_check_err(struct bpf_gen *gen)
|
||||||
|
{
|
||||||
|
__s64 off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 1;
|
||||||
|
|
||||||
|
/* R7 contains result of last sys_bpf command.
|
||||||
|
* if (R7 < 0) goto cleanup;
|
||||||
|
*/
|
||||||
|
if (is_simm16(off)) {
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JSLT, BPF_REG_7, 0, off));
|
||||||
|
} else {
|
||||||
|
gen->error = -ERANGE;
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reg1 and reg2 should not be R1 - R5. They can be R0, R6 - R10 */
|
||||||
|
static void emit_debug(struct bpf_gen *gen, int reg1, int reg2,
|
||||||
|
const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int addr, len, ret;
|
||||||
|
|
||||||
|
if (!gen->log_level)
|
||||||
|
return;
|
||||||
|
ret = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
|
if (ret < 1024 - 7 && reg1 >= 0 && reg2 < 0)
|
||||||
|
/* The special case to accommodate common debug_ret():
|
||||||
|
* to avoid specifying BPF_REG_7 and adding " r=%%d" to
|
||||||
|
* prints explicitly.
|
||||||
|
*/
|
||||||
|
strcat(buf, " r=%d");
|
||||||
|
len = strlen(buf) + 1;
|
||||||
|
addr = add_data(gen, buf, len);
|
||||||
|
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, addr));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
|
||||||
|
if (reg1 >= 0)
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_3, reg1));
|
||||||
|
if (reg2 >= 0)
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_4, reg2));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_trace_printk));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_regs(struct bpf_gen *gen, int reg1, int reg2, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
emit_debug(gen, reg1, reg2, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_ret(struct bpf_gen *gen, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
emit_debug(gen, BPF_REG_7, -1, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __emit_sys_close(struct bpf_gen *gen)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0,
|
||||||
|
/* 2 is the number of the following insns
|
||||||
|
* * 6 is additional insns in debug_regs
|
||||||
|
*/
|
||||||
|
2 + (gen->log_level ? 6 : 0)));
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_1));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
|
||||||
|
debug_regs(gen, BPF_REG_9, BPF_REG_0, "close(%%d) = %%d");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_sys_close_stack(struct bpf_gen *gen, int stack_off)
|
||||||
|
{
|
||||||
|
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, stack_off));
|
||||||
|
__emit_sys_close(gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
|
||||||
|
{
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, blob_off));
|
||||||
|
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0));
|
||||||
|
__emit_sys_close(gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_gen__finish(struct bpf_gen *gen)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emit_sys_close_stack(gen, stack_off(btf_fd));
|
||||||
|
for (i = 0; i < gen->nr_progs; i++)
|
||||||
|
move_stack2ctx(gen,
|
||||||
|
sizeof(struct bpf_loader_ctx) +
|
||||||
|
sizeof(struct bpf_map_desc) * gen->nr_maps +
|
||||||
|
sizeof(struct bpf_prog_desc) * i +
|
||||||
|
offsetof(struct bpf_prog_desc, prog_fd), 4,
|
||||||
|
stack_off(prog_fd[i]));
|
||||||
|
for (i = 0; i < gen->nr_maps; i++)
|
||||||
|
move_stack2ctx(gen,
|
||||||
|
sizeof(struct bpf_loader_ctx) +
|
||||||
|
sizeof(struct bpf_map_desc) * i +
|
||||||
|
offsetof(struct bpf_map_desc, map_fd), 4,
|
||||||
|
stack_off(map_fd[i]));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0));
|
||||||
|
emit(gen, BPF_EXIT_INSN());
|
||||||
|
pr_debug("gen: finish %d\n", gen->error);
|
||||||
|
if (!gen->error) {
|
||||||
|
struct gen_loader_opts *opts = gen->opts;
|
||||||
|
|
||||||
|
opts->insns = gen->insn_start;
|
||||||
|
opts->insns_sz = gen->insn_cur - gen->insn_start;
|
||||||
|
opts->data = gen->data_start;
|
||||||
|
opts->data_sz = gen->data_cur - gen->data_start;
|
||||||
|
}
|
||||||
|
return gen->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__free(struct bpf_gen *gen)
|
||||||
|
{
|
||||||
|
if (!gen)
|
||||||
|
return;
|
||||||
|
free(gen->data_start);
|
||||||
|
free(gen->insn_start);
|
||||||
|
free(gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
|
||||||
|
__u32 btf_raw_size)
|
||||||
|
{
|
||||||
|
int attr_size = offsetofend(union bpf_attr, btf_log_level);
|
||||||
|
int btf_data, btf_load_attr;
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_size);
|
||||||
|
pr_debug("gen: load_btf: size %d\n", btf_raw_size);
|
||||||
|
btf_data = add_data(gen, btf_raw_data, btf_raw_size);
|
||||||
|
|
||||||
|
attr.btf_size = btf_raw_size;
|
||||||
|
btf_load_attr = add_data(gen, &attr, attr_size);
|
||||||
|
|
||||||
|
/* populate union bpf_attr with user provided log details */
|
||||||
|
move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_level), 4,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_level), false);
|
||||||
|
move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_size), 4,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_size), false);
|
||||||
|
move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_buf), 8,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_buf), false);
|
||||||
|
/* populate union bpf_attr with a pointer to the BTF data */
|
||||||
|
emit_rel_store(gen, attr_field(btf_load_attr, btf), btf_data);
|
||||||
|
/* emit BTF_LOAD command */
|
||||||
|
emit_sys_bpf(gen, BPF_BTF_LOAD, btf_load_attr, attr_size);
|
||||||
|
debug_ret(gen, "btf_load size %d", btf_raw_size);
|
||||||
|
emit_check_err(gen);
|
||||||
|
/* remember btf_fd in the stack, if successful */
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7, stack_off(btf_fd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__map_create(struct bpf_gen *gen,
|
||||||
|
struct bpf_create_map_attr *map_attr, int map_idx)
|
||||||
|
{
|
||||||
|
int attr_size = offsetofend(union bpf_attr, btf_vmlinux_value_type_id);
|
||||||
|
bool close_inner_map_fd = false;
|
||||||
|
int map_create_attr;
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_size);
|
||||||
|
attr.map_type = map_attr->map_type;
|
||||||
|
attr.key_size = map_attr->key_size;
|
||||||
|
attr.value_size = map_attr->value_size;
|
||||||
|
attr.map_flags = map_attr->map_flags;
|
||||||
|
memcpy(attr.map_name, map_attr->name,
|
||||||
|
min((unsigned)strlen(map_attr->name), BPF_OBJ_NAME_LEN - 1));
|
||||||
|
attr.numa_node = map_attr->numa_node;
|
||||||
|
attr.map_ifindex = map_attr->map_ifindex;
|
||||||
|
attr.max_entries = map_attr->max_entries;
|
||||||
|
switch (attr.map_type) {
|
||||||
|
case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
|
||||||
|
case BPF_MAP_TYPE_CGROUP_ARRAY:
|
||||||
|
case BPF_MAP_TYPE_STACK_TRACE:
|
||||||
|
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||||
|
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||||
|
case BPF_MAP_TYPE_DEVMAP:
|
||||||
|
case BPF_MAP_TYPE_DEVMAP_HASH:
|
||||||
|
case BPF_MAP_TYPE_CPUMAP:
|
||||||
|
case BPF_MAP_TYPE_XSKMAP:
|
||||||
|
case BPF_MAP_TYPE_SOCKMAP:
|
||||||
|
case BPF_MAP_TYPE_SOCKHASH:
|
||||||
|
case BPF_MAP_TYPE_QUEUE:
|
||||||
|
case BPF_MAP_TYPE_STACK:
|
||||||
|
case BPF_MAP_TYPE_RINGBUF:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
attr.btf_key_type_id = map_attr->btf_key_type_id;
|
||||||
|
attr.btf_value_type_id = map_attr->btf_value_type_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("gen: map_create: %s idx %d type %d value_type_id %d\n",
|
||||||
|
attr.map_name, map_idx, map_attr->map_type, attr.btf_value_type_id);
|
||||||
|
|
||||||
|
map_create_attr = add_data(gen, &attr, attr_size);
|
||||||
|
if (attr.btf_value_type_id)
|
||||||
|
/* populate union bpf_attr with btf_fd saved in the stack earlier */
|
||||||
|
move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
|
||||||
|
stack_off(btf_fd));
|
||||||
|
switch (attr.map_type) {
|
||||||
|
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||||
|
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||||
|
move_stack2blob(gen, attr_field(map_create_attr, inner_map_fd), 4,
|
||||||
|
stack_off(inner_map_fd));
|
||||||
|
close_inner_map_fd = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* conditionally update max_entries */
|
||||||
|
if (map_idx >= 0)
|
||||||
|
move_ctx2blob(gen, attr_field(map_create_attr, max_entries), 4,
|
||||||
|
sizeof(struct bpf_loader_ctx) +
|
||||||
|
sizeof(struct bpf_map_desc) * map_idx +
|
||||||
|
offsetof(struct bpf_map_desc, max_entries),
|
||||||
|
true /* check that max_entries != 0 */);
|
||||||
|
/* emit MAP_CREATE command */
|
||||||
|
emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size);
|
||||||
|
debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d",
|
||||||
|
attr.map_name, map_idx, map_attr->map_type, attr.value_size,
|
||||||
|
attr.btf_value_type_id);
|
||||||
|
emit_check_err(gen);
|
||||||
|
/* remember map_fd in the stack, if successful */
|
||||||
|
if (map_idx < 0) {
|
||||||
|
/* This bpf_gen__map_create() function is called with map_idx >= 0
|
||||||
|
* for all maps that libbpf loading logic tracks.
|
||||||
|
* It's called with -1 to create an inner map.
|
||||||
|
*/
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7,
|
||||||
|
stack_off(inner_map_fd)));
|
||||||
|
} else if (map_idx != gen->nr_maps) {
|
||||||
|
gen->error = -EDOM; /* internal bug */
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7,
|
||||||
|
stack_off(map_fd[map_idx])));
|
||||||
|
gen->nr_maps++;
|
||||||
|
}
|
||||||
|
if (close_inner_map_fd)
|
||||||
|
emit_sys_close_stack(gen, stack_off(inner_map_fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *attach_name,
|
||||||
|
enum bpf_attach_type type)
|
||||||
|
{
|
||||||
|
const char *prefix;
|
||||||
|
int kind, ret;
|
||||||
|
|
||||||
|
btf_get_kernel_prefix_kind(type, &prefix, &kind);
|
||||||
|
gen->attach_kind = kind;
|
||||||
|
ret = snprintf(gen->attach_target, sizeof(gen->attach_target), "%s%s",
|
||||||
|
prefix, attach_name);
|
||||||
|
if (ret == sizeof(gen->attach_target))
|
||||||
|
gen->error = -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_find_attach_target(struct bpf_gen *gen)
|
||||||
|
{
|
||||||
|
int name, len = strlen(gen->attach_target) + 1;
|
||||||
|
|
||||||
|
pr_debug("gen: find_attach_tgt %s %d\n", gen->attach_target, gen->attach_kind);
|
||||||
|
name = add_data(gen, gen->attach_target, len);
|
||||||
|
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, name));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_3, gen->attach_kind));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_4, 0));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_btf_find_by_name_kind));
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
|
||||||
|
debug_ret(gen, "find_by_name_kind(%s,%d)",
|
||||||
|
gen->attach_target, gen->attach_kind);
|
||||||
|
emit_check_err(gen);
|
||||||
|
/* if successful, btf_id is in lower 32-bit of R7 and
|
||||||
|
* btf_obj_fd is in upper 32-bit
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, int kind,
|
||||||
|
int insn_idx)
|
||||||
|
{
|
||||||
|
struct ksym_relo_desc *relo;
|
||||||
|
|
||||||
|
relo = libbpf_reallocarray(gen->relos, gen->relo_cnt + 1, sizeof(*relo));
|
||||||
|
if (!relo) {
|
||||||
|
gen->error = -ENOMEM;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gen->relos = relo;
|
||||||
|
relo += gen->relo_cnt;
|
||||||
|
relo->name = name;
|
||||||
|
relo->kind = kind;
|
||||||
|
relo->insn_idx = insn_idx;
|
||||||
|
gen->relo_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insns)
|
||||||
|
{
|
||||||
|
int name, insn, len = strlen(relo->name) + 1;
|
||||||
|
|
||||||
|
pr_debug("gen: emit_relo: %s at %d\n", relo->name, relo->insn_idx);
|
||||||
|
name = add_data(gen, relo->name, len);
|
||||||
|
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, name));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_3, relo->kind));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_4, 0));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_btf_find_by_name_kind));
|
||||||
|
emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
|
||||||
|
debug_ret(gen, "find_by_name_kind(%s,%d)", relo->name, relo->kind);
|
||||||
|
emit_check_err(gen);
|
||||||
|
/* store btf_id into insn[insn_idx].imm */
|
||||||
|
insn = insns + sizeof(struct bpf_insn) * relo->insn_idx +
|
||||||
|
offsetof(struct bpf_insn, imm);
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, insn));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7, 0));
|
||||||
|
if (relo->kind == BTF_KIND_VAR) {
|
||||||
|
/* store btf_obj_fd into insn[insn_idx + 1].imm */
|
||||||
|
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 32));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7,
|
||||||
|
sizeof(struct bpf_insn)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_relos(struct bpf_gen *gen, int insns)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < gen->relo_cnt; i++)
|
||||||
|
emit_relo(gen, gen->relos + i, insns);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||||
|
{
|
||||||
|
int i, insn;
|
||||||
|
|
||||||
|
for (i = 0; i < gen->relo_cnt; i++) {
|
||||||
|
if (gen->relos[i].kind != BTF_KIND_VAR)
|
||||||
|
continue;
|
||||||
|
/* close fd recorded in insn[insn_idx + 1].imm */
|
||||||
|
insn = insns +
|
||||||
|
sizeof(struct bpf_insn) * (gen->relos[i].insn_idx + 1) +
|
||||||
|
offsetof(struct bpf_insn, imm);
|
||||||
|
emit_sys_close_blob(gen, insn);
|
||||||
|
}
|
||||||
|
if (gen->relo_cnt) {
|
||||||
|
free(gen->relos);
|
||||||
|
gen->relo_cnt = 0;
|
||||||
|
gen->relos = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||||
|
struct bpf_prog_load_params *load_attr, int prog_idx)
|
||||||
|
{
|
||||||
|
int attr_size = offsetofend(union bpf_attr, fd_array);
|
||||||
|
int prog_load_attr, license, insns, func_info, line_info;
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_size);
|
||||||
|
pr_debug("gen: prog_load: type %d insns_cnt %zd\n",
|
||||||
|
load_attr->prog_type, load_attr->insn_cnt);
|
||||||
|
/* add license string to blob of bytes */
|
||||||
|
license = add_data(gen, load_attr->license, strlen(load_attr->license) + 1);
|
||||||
|
/* add insns to blob of bytes */
|
||||||
|
insns = add_data(gen, load_attr->insns,
|
||||||
|
load_attr->insn_cnt * sizeof(struct bpf_insn));
|
||||||
|
|
||||||
|
attr.prog_type = load_attr->prog_type;
|
||||||
|
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||||
|
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||||
|
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||||
|
attr.kern_version = 0;
|
||||||
|
attr.insn_cnt = (__u32)load_attr->insn_cnt;
|
||||||
|
attr.prog_flags = load_attr->prog_flags;
|
||||||
|
|
||||||
|
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||||
|
attr.func_info_cnt = load_attr->func_info_cnt;
|
||||||
|
func_info = add_data(gen, load_attr->func_info,
|
||||||
|
attr.func_info_cnt * attr.func_info_rec_size);
|
||||||
|
|
||||||
|
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||||
|
attr.line_info_cnt = load_attr->line_info_cnt;
|
||||||
|
line_info = add_data(gen, load_attr->line_info,
|
||||||
|
attr.line_info_cnt * attr.line_info_rec_size);
|
||||||
|
|
||||||
|
memcpy(attr.prog_name, load_attr->name,
|
||||||
|
min((unsigned)strlen(load_attr->name), BPF_OBJ_NAME_LEN - 1));
|
||||||
|
prog_load_attr = add_data(gen, &attr, attr_size);
|
||||||
|
|
||||||
|
/* populate union bpf_attr with a pointer to license */
|
||||||
|
emit_rel_store(gen, attr_field(prog_load_attr, license), license);
|
||||||
|
|
||||||
|
/* populate union bpf_attr with a pointer to instructions */
|
||||||
|
emit_rel_store(gen, attr_field(prog_load_attr, insns), insns);
|
||||||
|
|
||||||
|
/* populate union bpf_attr with a pointer to func_info */
|
||||||
|
emit_rel_store(gen, attr_field(prog_load_attr, func_info), func_info);
|
||||||
|
|
||||||
|
/* populate union bpf_attr with a pointer to line_info */
|
||||||
|
emit_rel_store(gen, attr_field(prog_load_attr, line_info), line_info);
|
||||||
|
|
||||||
|
/* populate union bpf_attr fd_array with a pointer to stack where map_fds are saved */
|
||||||
|
emit_rel_store_sp(gen, attr_field(prog_load_attr, fd_array),
|
||||||
|
stack_off(map_fd[0]));
|
||||||
|
|
||||||
|
/* populate union bpf_attr with user provided log details */
|
||||||
|
move_ctx2blob(gen, attr_field(prog_load_attr, log_level), 4,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_level), false);
|
||||||
|
move_ctx2blob(gen, attr_field(prog_load_attr, log_size), 4,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_size), false);
|
||||||
|
move_ctx2blob(gen, attr_field(prog_load_attr, log_buf), 8,
|
||||||
|
offsetof(struct bpf_loader_ctx, log_buf), false);
|
||||||
|
/* populate union bpf_attr with btf_fd saved in the stack earlier */
|
||||||
|
move_stack2blob(gen, attr_field(prog_load_attr, prog_btf_fd), 4,
|
||||||
|
stack_off(btf_fd));
|
||||||
|
if (gen->attach_kind) {
|
||||||
|
emit_find_attach_target(gen);
|
||||||
|
/* populate union bpf_attr with btf_id and btf_obj_fd found by helper */
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, prog_load_attr));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7,
|
||||||
|
offsetof(union bpf_attr, attach_btf_id)));
|
||||||
|
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 32));
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_7,
|
||||||
|
offsetof(union bpf_attr, attach_btf_obj_fd)));
|
||||||
|
}
|
||||||
|
emit_relos(gen, insns);
|
||||||
|
/* emit PROG_LOAD command */
|
||||||
|
emit_sys_bpf(gen, BPF_PROG_LOAD, prog_load_attr, attr_size);
|
||||||
|
debug_ret(gen, "prog_load %s insn_cnt %d", attr.prog_name, attr.insn_cnt);
|
||||||
|
/* successful or not, close btf module FDs used in extern ksyms and attach_btf_obj_fd */
|
||||||
|
cleanup_relos(gen, insns);
|
||||||
|
if (gen->attach_kind)
|
||||||
|
emit_sys_close_blob(gen,
|
||||||
|
attr_field(prog_load_attr, attach_btf_obj_fd));
|
||||||
|
emit_check_err(gen);
|
||||||
|
/* remember prog_fd in the stack, if successful */
|
||||||
|
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7,
|
||||||
|
stack_off(prog_fd[gen->nr_progs])));
|
||||||
|
gen->nr_progs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
|
||||||
|
__u32 value_size)
|
||||||
|
{
|
||||||
|
int attr_size = offsetofend(union bpf_attr, flags);
|
||||||
|
int map_update_attr, value, key;
|
||||||
|
union bpf_attr attr;
|
||||||
|
int zero = 0;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_size);
|
||||||
|
pr_debug("gen: map_update_elem: idx %d\n", map_idx);
|
||||||
|
|
||||||
|
value = add_data(gen, pvalue, value_size);
|
||||||
|
key = add_data(gen, &zero, sizeof(zero));
|
||||||
|
|
||||||
|
/* if (map_desc[map_idx].initial_value)
|
||||||
|
* copy_from_user(value, initial_value, value_size);
|
||||||
|
*/
|
||||||
|
emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_6,
|
||||||
|
sizeof(struct bpf_loader_ctx) +
|
||||||
|
sizeof(struct bpf_map_desc) * map_idx +
|
||||||
|
offsetof(struct bpf_map_desc, initial_value)));
|
||||||
|
emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 4));
|
||||||
|
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||||
|
0, 0, 0, value));
|
||||||
|
emit(gen, BPF_MOV64_IMM(BPF_REG_2, value_size));
|
||||||
|
emit(gen, BPF_EMIT_CALL(BPF_FUNC_copy_from_user));
|
||||||
|
|
||||||
|
map_update_attr = add_data(gen, &attr, attr_size);
|
||||||
|
move_stack2blob(gen, attr_field(map_update_attr, map_fd), 4,
|
||||||
|
stack_off(map_fd[map_idx]));
|
||||||
|
emit_rel_store(gen, attr_field(map_update_attr, key), key);
|
||||||
|
emit_rel_store(gen, attr_field(map_update_attr, value), value);
|
||||||
|
/* emit MAP_UPDATE_ELEM command */
|
||||||
|
emit_sys_bpf(gen, BPF_MAP_UPDATE_ELEM, map_update_attr, attr_size);
|
||||||
|
debug_ret(gen, "update_elem idx %d value_size %d", map_idx, value_size);
|
||||||
|
emit_check_err(gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx)
|
||||||
|
{
|
||||||
|
int attr_size = offsetofend(union bpf_attr, map_fd);
|
||||||
|
int map_freeze_attr;
|
||||||
|
union bpf_attr attr;
|
||||||
|
|
||||||
|
memset(&attr, 0, attr_size);
|
||||||
|
pr_debug("gen: map_freeze: idx %d\n", map_idx);
|
||||||
|
map_freeze_attr = add_data(gen, &attr, attr_size);
|
||||||
|
move_stack2blob(gen, attr_field(map_freeze_attr, map_fd), 4,
|
||||||
|
stack_off(map_fd[map_idx]));
|
||||||
|
/* emit MAP_FREEZE command */
|
||||||
|
emit_sys_bpf(gen, BPF_MAP_FREEZE, map_freeze_attr, attr_size);
|
||||||
|
debug_ret(gen, "map_freeze");
|
||||||
|
emit_check_err(gen);
|
||||||
|
}
|
||||||
3603
src/libbpf.c
3603
src/libbpf.c
File diff suppressed because it is too large
Load Diff
162
src/libbpf.h
162
src/libbpf.h
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
|
|
||||||
#include "libbpf_common.h"
|
#include "libbpf_common.h"
|
||||||
|
#include "libbpf_legacy.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -93,8 +94,15 @@ struct bpf_object_open_opts {
|
|||||||
* system Kconfig for CONFIG_xxx externs.
|
* system Kconfig for CONFIG_xxx externs.
|
||||||
*/
|
*/
|
||||||
const char *kconfig;
|
const char *kconfig;
|
||||||
|
/* Path to the custom BTF to be used for BPF CO-RE relocations.
|
||||||
|
* This custom BTF completely replaces the use of vmlinux BTF
|
||||||
|
* for the purpose of CO-RE relocations.
|
||||||
|
* NOTE: any other BPF feature (e.g., fentry/fexit programs,
|
||||||
|
* struct_ops, etc) will need actual kernel BTF at /sys/kernel/btf/vmlinux.
|
||||||
|
*/
|
||||||
|
const char *btf_custom_path;
|
||||||
};
|
};
|
||||||
#define bpf_object_open_opts__last_field kconfig
|
#define bpf_object_open_opts__last_field btf_custom_path
|
||||||
|
|
||||||
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
LIBBPF_API struct bpf_object *bpf_object__open(const char *path);
|
||||||
LIBBPF_API struct bpf_object *
|
LIBBPF_API struct bpf_object *
|
||||||
@@ -143,6 +151,7 @@ LIBBPF_API int bpf_object__unload(struct bpf_object *obj);
|
|||||||
|
|
||||||
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
LIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);
|
||||||
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
LIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);
|
||||||
|
LIBBPF_API int bpf_object__set_kversion(struct bpf_object *obj, __u32 kern_version);
|
||||||
|
|
||||||
struct btf;
|
struct btf;
|
||||||
LIBBPF_API struct btf *bpf_object__btf(const struct bpf_object *obj);
|
LIBBPF_API struct btf *bpf_object__btf(const struct bpf_object *obj);
|
||||||
@@ -235,20 +244,86 @@ LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
|||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach(struct bpf_program *prog);
|
bpf_program__attach(struct bpf_program *prog);
|
||||||
|
|
||||||
|
struct bpf_perf_event_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
};
|
||||||
|
#define bpf_perf_event_opts__last_field bpf_cookie
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
|
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,
|
||||||
|
const struct bpf_perf_event_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_kprobe_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
/* function's offset to install kprobe to */
|
||||||
|
unsigned long offset;
|
||||||
|
/* kprobe is return probe */
|
||||||
|
bool retprobe;
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_kprobe_opts__last_field retprobe
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
|
bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
|
||||||
const char *func_name);
|
const char *func_name);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_kprobe_opts(struct bpf_program *prog,
|
||||||
|
const char *func_name,
|
||||||
|
const struct bpf_kprobe_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_uprobe_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* offset of kernel reference counted USDT semaphore, added in
|
||||||
|
* a6ca88b241d5 ("trace_uprobe: support reference counter in fd-based uprobe")
|
||||||
|
*/
|
||||||
|
size_t ref_ctr_offset;
|
||||||
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
/* uprobe is return probe, invoked at function return time */
|
||||||
|
bool retprobe;
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_uprobe_opts__last_field retprobe
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
|
bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
|
||||||
pid_t pid, const char *binary_path,
|
pid_t pid, const char *binary_path,
|
||||||
size_t func_offset);
|
size_t func_offset);
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,
|
||||||
|
const char *binary_path, size_t func_offset,
|
||||||
|
const struct bpf_uprobe_opts *opts);
|
||||||
|
|
||||||
|
struct bpf_tracepoint_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
/* custom user-provided value fetchable through bpf_get_attach_cookie() */
|
||||||
|
__u64 bpf_cookie;
|
||||||
|
};
|
||||||
|
#define bpf_tracepoint_opts__last_field bpf_cookie
|
||||||
|
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_tracepoint(struct bpf_program *prog,
|
bpf_program__attach_tracepoint(struct bpf_program *prog,
|
||||||
const char *tp_category,
|
const char *tp_category,
|
||||||
const char *tp_name);
|
const char *tp_name);
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
|
bpf_program__attach_tracepoint_opts(struct bpf_program *prog,
|
||||||
|
const char *tp_category,
|
||||||
|
const char *tp_name,
|
||||||
|
const struct bpf_tracepoint_opts *opts);
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_link *
|
||||||
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||||
const char *tp_name);
|
const char *tp_name);
|
||||||
LIBBPF_API struct bpf_link *
|
LIBBPF_API struct bpf_link *
|
||||||
@@ -361,12 +436,12 @@ LIBBPF_API int bpf_program__set_struct_ops(struct bpf_program *prog);
|
|||||||
LIBBPF_API int bpf_program__set_extension(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__set_extension(struct bpf_program *prog);
|
||||||
LIBBPF_API int bpf_program__set_sk_lookup(struct bpf_program *prog);
|
LIBBPF_API int bpf_program__set_sk_lookup(struct bpf_program *prog);
|
||||||
|
|
||||||
LIBBPF_API enum bpf_prog_type bpf_program__get_type(struct bpf_program *prog);
|
LIBBPF_API enum bpf_prog_type bpf_program__get_type(const struct bpf_program *prog);
|
||||||
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
|
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
|
||||||
enum bpf_prog_type type);
|
enum bpf_prog_type type);
|
||||||
|
|
||||||
LIBBPF_API enum bpf_attach_type
|
LIBBPF_API enum bpf_attach_type
|
||||||
bpf_program__get_expected_attach_type(struct bpf_program *prog);
|
bpf_program__get_expected_attach_type(const struct bpf_program *prog);
|
||||||
LIBBPF_API void
|
LIBBPF_API void
|
||||||
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||||
enum bpf_attach_type type);
|
enum bpf_attach_type type);
|
||||||
@@ -470,15 +545,18 @@ LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
|||||||
LIBBPF_API void *bpf_map__priv(const struct bpf_map *map);
|
LIBBPF_API void *bpf_map__priv(const struct bpf_map *map);
|
||||||
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
||||||
const void *data, size_t size);
|
const void *data, size_t size);
|
||||||
|
LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);
|
||||||
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
||||||
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
|
||||||
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
|
||||||
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
|
||||||
|
LIBBPF_API const char *bpf_map__pin_path(const struct bpf_map *map);
|
||||||
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
|
||||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||||
|
|
||||||
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
||||||
|
LIBBPF_API struct bpf_map *bpf_map__inner_map(struct bpf_map *map);
|
||||||
|
|
||||||
LIBBPF_API long libbpf_get_error(const void *ptr);
|
LIBBPF_API long libbpf_get_error(const void *ptr);
|
||||||
|
|
||||||
@@ -496,6 +574,7 @@ LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
|||||||
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
||||||
struct bpf_object **pobj, int *prog_fd);
|
struct bpf_object **pobj, int *prog_fd);
|
||||||
|
|
||||||
|
/* XDP related API */
|
||||||
struct xdp_link_info {
|
struct xdp_link_info {
|
||||||
__u32 prog_id;
|
__u32 prog_id;
|
||||||
__u32 drv_prog_id;
|
__u32 drv_prog_id;
|
||||||
@@ -507,6 +586,7 @@ struct xdp_link_info {
|
|||||||
struct bpf_xdp_set_link_opts {
|
struct bpf_xdp_set_link_opts {
|
||||||
size_t sz;
|
size_t sz;
|
||||||
int old_fd;
|
int old_fd;
|
||||||
|
size_t :0;
|
||||||
};
|
};
|
||||||
#define bpf_xdp_set_link_opts__last_field old_fd
|
#define bpf_xdp_set_link_opts__last_field old_fd
|
||||||
|
|
||||||
@@ -517,6 +597,49 @@ LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
|||||||
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||||
size_t info_size, __u32 flags);
|
size_t info_size, __u32 flags);
|
||||||
|
|
||||||
|
/* TC related API */
|
||||||
|
enum bpf_tc_attach_point {
|
||||||
|
BPF_TC_INGRESS = 1 << 0,
|
||||||
|
BPF_TC_EGRESS = 1 << 1,
|
||||||
|
BPF_TC_CUSTOM = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BPF_TC_PARENT(a, b) \
|
||||||
|
((((a) << 16) & 0xFFFF0000U) | ((b) & 0x0000FFFFU))
|
||||||
|
|
||||||
|
enum bpf_tc_flags {
|
||||||
|
BPF_TC_F_REPLACE = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_tc_hook {
|
||||||
|
size_t sz;
|
||||||
|
int ifindex;
|
||||||
|
enum bpf_tc_attach_point attach_point;
|
||||||
|
__u32 parent;
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_tc_hook__last_field parent
|
||||||
|
|
||||||
|
struct bpf_tc_opts {
|
||||||
|
size_t sz;
|
||||||
|
int prog_fd;
|
||||||
|
__u32 flags;
|
||||||
|
__u32 prog_id;
|
||||||
|
__u32 handle;
|
||||||
|
__u32 priority;
|
||||||
|
size_t :0;
|
||||||
|
};
|
||||||
|
#define bpf_tc_opts__last_field priority
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_tc_hook_create(struct bpf_tc_hook *hook);
|
||||||
|
LIBBPF_API int bpf_tc_hook_destroy(struct bpf_tc_hook *hook);
|
||||||
|
LIBBPF_API int bpf_tc_attach(const struct bpf_tc_hook *hook,
|
||||||
|
struct bpf_tc_opts *opts);
|
||||||
|
LIBBPF_API int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||||
|
const struct bpf_tc_opts *opts);
|
||||||
|
LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,
|
||||||
|
struct bpf_tc_opts *opts);
|
||||||
|
|
||||||
/* Ring buffer APIs */
|
/* Ring buffer APIs */
|
||||||
struct ring_buffer;
|
struct ring_buffer;
|
||||||
|
|
||||||
@@ -753,12 +876,45 @@ LIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s);
|
|||||||
LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);
|
LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);
|
||||||
LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);
|
LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);
|
||||||
|
|
||||||
|
struct gen_loader_opts {
|
||||||
|
size_t sz; /* size of this struct, for forward/backward compatiblity */
|
||||||
|
const char *data;
|
||||||
|
const char *insns;
|
||||||
|
__u32 data_sz;
|
||||||
|
__u32 insns_sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define gen_loader_opts__last_field insns_sz
|
||||||
|
LIBBPF_API int bpf_object__gen_loader(struct bpf_object *obj,
|
||||||
|
struct gen_loader_opts *opts);
|
||||||
|
|
||||||
enum libbpf_tristate {
|
enum libbpf_tristate {
|
||||||
TRI_NO = 0,
|
TRI_NO = 0,
|
||||||
TRI_YES = 1,
|
TRI_YES = 1,
|
||||||
TRI_MODULE = 2,
|
TRI_MODULE = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_linker_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
};
|
||||||
|
#define bpf_linker_opts__last_field sz
|
||||||
|
|
||||||
|
struct bpf_linker_file_opts {
|
||||||
|
/* size of this struct, for forward/backward compatiblity */
|
||||||
|
size_t sz;
|
||||||
|
};
|
||||||
|
#define bpf_linker_file_opts__last_field sz
|
||||||
|
|
||||||
|
struct bpf_linker;
|
||||||
|
|
||||||
|
LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts);
|
||||||
|
LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,
|
||||||
|
const char *filename,
|
||||||
|
const struct bpf_linker_file_opts *opts);
|
||||||
|
LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);
|
||||||
|
LIBBPF_API void bpf_linker__free(struct bpf_linker *linker);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -350,3 +350,39 @@ LIBBPF_0.3.0 {
|
|||||||
xsk_setup_xdp_prog;
|
xsk_setup_xdp_prog;
|
||||||
xsk_socket__update_xskmap;
|
xsk_socket__update_xskmap;
|
||||||
} LIBBPF_0.2.0;
|
} 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;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
|
#include "libbpf_internal.h"
|
||||||
|
|
||||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
@@ -39,7 +40,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
|
|||||||
int libbpf_strerror(int err, char *buf, size_t size)
|
int libbpf_strerror(int err, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
if (!buf || !size)
|
if (!buf || !size)
|
||||||
return -1;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
err = err > 0 ? err : -err;
|
err = err > 0 ? err : -err;
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
|||||||
|
|
||||||
ret = strerror_r(err, buf, size);
|
ret = strerror_r(err, buf, size);
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
return ret;
|
return libbpf_err_errno(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err < __LIBBPF_ERRNO__END) {
|
if (err < __LIBBPF_ERRNO__END) {
|
||||||
@@ -62,5 +63,5 @@ int libbpf_strerror(int err, char *buf, size_t size)
|
|||||||
|
|
||||||
snprintf(buf, size, "Unknown libbpf error %d", err);
|
snprintf(buf, size, "Unknown libbpf error %d", err);
|
||||||
buf[size - 1] = '\0';
|
buf[size - 1] = '\0';
|
||||||
return -1;
|
return libbpf_err(-ENOENT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include "libbpf_legacy.h"
|
||||||
|
#include "relo_core.h"
|
||||||
|
|
||||||
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
/* make sure libbpf doesn't use kernel-only integer typedefs */
|
||||||
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
#pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
|
||||||
@@ -19,6 +23,38 @@
|
|||||||
#pragma GCC poison reallocarray
|
#pragma GCC poison reallocarray
|
||||||
|
|
||||||
#include "libbpf.h"
|
#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 GELF_ST_VISIBILITY
|
||||||
|
#define GELF_ST_VISIBILITY(o) ((o) & 0x03)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
||||||
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
|
||||||
@@ -31,6 +67,8 @@
|
|||||||
#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
|
#define BTF_MEMBER_ENC(name, type, bits_offset) (name), (type), (bits_offset)
|
||||||
#define BTF_PARAM_ENC(name, type) (name), (type)
|
#define BTF_PARAM_ENC(name, type) (name), (type)
|
||||||
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
#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)
|
||||||
|
|
||||||
#ifndef likely
|
#ifndef likely
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
@@ -105,9 +143,69 @@ static inline void *libbpf_reallocarray(void *ptr, size_t nmemb, size_t size)
|
|||||||
return realloc(ptr, total);
|
return realloc(ptr, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *btf_add_mem(void **data, size_t *cap_cnt, size_t elem_sz,
|
struct btf;
|
||||||
size_t cur_cnt, size_t max_cnt, size_t add_cnt);
|
struct btf_type;
|
||||||
int btf_ensure_mem(void **data, size_t *cap_cnt, size_t elem_sz, size_t need_cnt);
|
|
||||||
|
struct btf_type *btf_type_by_id(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_ALL = 0x3ff, /* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
static inline bool libbpf_validate_opts(const char *opts,
|
||||||
size_t opts_sz, size_t user_sz,
|
size_t opts_sz, size_t user_sz,
|
||||||
@@ -117,16 +215,9 @@ static inline bool libbpf_validate_opts(const char *opts,
|
|||||||
pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
pr_warn("%s size (%zu) is too small\n", type_name, user_sz);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (user_sz > opts_sz) {
|
if (!libbpf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {
|
||||||
size_t i;
|
pr_warn("%s has non-zero extra bytes\n", type_name);
|
||||||
|
return false;
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -146,6 +237,14 @@ static inline bool libbpf_validate_opts(const char *opts,
|
|||||||
(opts)->field = value; \
|
(opts)->field = value; \
|
||||||
} while (0)
|
} 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); \
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz);
|
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 parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||||
@@ -186,6 +285,8 @@ int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
|||||||
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
||||||
__u32 *off);
|
__u32 *off);
|
||||||
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
|
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);
|
||||||
|
|
||||||
struct btf_ext_info {
|
struct btf_ext_info {
|
||||||
/*
|
/*
|
||||||
@@ -278,75 +379,72 @@ struct bpf_line_info_min {
|
|||||||
__u32 line_col;
|
__u32 line_col;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* bpf_core_relo_kind encodes which aspect of captured field/type/enum value
|
|
||||||
* has to be adjusted by relocations.
|
|
||||||
*/
|
|
||||||
enum bpf_core_relo_kind {
|
|
||||||
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
|
||||||
BPF_FIELD_BYTE_SIZE = 1, /* field size in bytes */
|
|
||||||
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
|
||||||
BPF_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */
|
|
||||||
BPF_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */
|
|
||||||
BPF_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */
|
|
||||||
BPF_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */
|
|
||||||
BPF_TYPE_ID_TARGET = 7, /* type ID in target kernel */
|
|
||||||
BPF_TYPE_EXISTS = 8, /* type existence in target kernel */
|
|
||||||
BPF_TYPE_SIZE = 9, /* type size in bytes */
|
|
||||||
BPF_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */
|
|
||||||
BPF_ENUMVAL_VALUE = 11, /* enum value integer value */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The minimum bpf_core_relo checked by the loader
|
typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);
|
||||||
*
|
typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);
|
||||||
* CO-RE relocation captures the following data:
|
int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx);
|
||||||
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx);
|
||||||
* its insn->imm field to be relocated with actual field info;
|
int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
|
||||||
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
|
||||||
* type or field;
|
|
||||||
* - access_str_off - offset into corresponding .BTF string section. String
|
extern enum libbpf_strict_mode libbpf_mode;
|
||||||
* interpretation depends on specific relocation kind:
|
|
||||||
* - for field-based relocations, string encodes an accessed field using
|
/* handle direct returned errors */
|
||||||
* a sequence of field and array indices, separated by colon (:). It's
|
static inline int libbpf_err(int ret)
|
||||||
* conceptually very close to LLVM's getelementptr ([0]) instruction's
|
{
|
||||||
* arguments for identifying offset to a field.
|
if (ret < 0)
|
||||||
* - for type-based relocations, strings is expected to be just "0";
|
errno = -ret;
|
||||||
* - for enum value-based relocations, string contains an index of enum
|
return ret;
|
||||||
* value within its enum type;
|
}
|
||||||
*
|
|
||||||
* Example to provide a better feel.
|
/* handle errno-based (e.g., syscall or libc) errors according to libbpf's
|
||||||
*
|
* strict mode settings
|
||||||
* struct sample {
|
|
||||||
* int a;
|
|
||||||
* struct {
|
|
||||||
* int b[10];
|
|
||||||
* };
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* struct sample *s = ...;
|
|
||||||
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
|
||||||
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
|
||||||
* // b is field #0 inside anon struct, accessing elem #5)
|
|
||||||
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
|
||||||
*
|
|
||||||
* type_id for all relocs in this example will capture BTF type id of
|
|
||||||
* `struct sample`.
|
|
||||||
*
|
|
||||||
* Such relocation is emitted when using __builtin_preserve_access_index()
|
|
||||||
* Clang built-in, passing expression that captures field address, e.g.:
|
|
||||||
*
|
|
||||||
* bpf_probe_read(&dst, sizeof(dst),
|
|
||||||
* __builtin_preserve_access_index(&src->a.b.c));
|
|
||||||
*
|
|
||||||
* In this case Clang will emit field relocation recording necessary data to
|
|
||||||
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
|
||||||
*
|
|
||||||
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
||||||
*/
|
*/
|
||||||
struct bpf_core_relo {
|
static inline int libbpf_err_errno(int ret)
|
||||||
__u32 insn_off;
|
{
|
||||||
__u32 type_id;
|
if (libbpf_mode & LIBBPF_STRICT_DIRECT_ERRS)
|
||||||
__u32 access_str_off;
|
/* errno is already assumed to be set on error */
|
||||||
enum bpf_core_relo_kind kind;
|
return ret < 0 ? -errno : ret;
|
||||||
};
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||||
|
|||||||
59
src/libbpf_legacy.h
Normal file
59
src/libbpf_legacy.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/* 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,
|
||||||
|
|
||||||
|
__LIBBPF_STRICT_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBBPF_API int libbpf_set_strict_mode(enum libbpf_strict_mode mode);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBBPF_LEGACY_BPF_H */
|
||||||
@@ -75,6 +75,9 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
|||||||
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
|
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
|
||||||
xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
||||||
break;
|
break;
|
||||||
|
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||||
|
xattr.expected_attach_type = BPF_CGROUP_GETSOCKOPT;
|
||||||
|
break;
|
||||||
case BPF_PROG_TYPE_SK_LOOKUP:
|
case BPF_PROG_TYPE_SK_LOOKUP:
|
||||||
xattr.expected_attach_type = BPF_SK_LOOKUP;
|
xattr.expected_attach_type = BPF_SK_LOOKUP;
|
||||||
break;
|
break;
|
||||||
@@ -104,7 +107,6 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
|||||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||||
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
|
||||||
case BPF_PROG_TYPE_TRACING:
|
case BPF_PROG_TYPE_TRACING:
|
||||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||||
case BPF_PROG_TYPE_EXT:
|
case BPF_PROG_TYPE_EXT:
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
/* 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
|
|
||||||
2892
src/linker.c
Normal file
2892
src/linker.c
Normal file
File diff suppressed because it is too large
Load Diff
578
src/netlink.c
578
src/netlink.c
@@ -4,7 +4,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/pkt_cls.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -40,7 +43,7 @@ static int libbpf_netlink_open(__u32 *nl_pid)
|
|||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
sa.nl_family = AF_NETLINK;
|
||||||
|
|
||||||
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@@ -73,9 +76,20 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
static void libbpf_netlink_close(int sock)
|
||||||
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
|
{
|
||||||
void *cookie)
|
close(sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NL_CONT,
|
||||||
|
NL_NEXT,
|
||||||
|
NL_DONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
||||||
|
__dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
bool multipart = true;
|
bool multipart = true;
|
||||||
struct nlmsgerr *err;
|
struct nlmsgerr *err;
|
||||||
@@ -84,6 +98,7 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
|||||||
int len, ret;
|
int len, ret;
|
||||||
|
|
||||||
while (multipart) {
|
while (multipart) {
|
||||||
|
start:
|
||||||
multipart = false;
|
multipart = false;
|
||||||
len = recv(sock, buf, sizeof(buf), 0);
|
len = recv(sock, buf, sizeof(buf), 0);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
@@ -121,8 +136,16 @@ static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
|
|||||||
}
|
}
|
||||||
if (_fn) {
|
if (_fn) {
|
||||||
ret = _fn(nh, fn, cookie);
|
ret = _fn(nh, fn, cookie);
|
||||||
if (ret)
|
switch (ret) {
|
||||||
|
case NL_CONT:
|
||||||
|
break;
|
||||||
|
case NL_NEXT:
|
||||||
|
goto start;
|
||||||
|
case NL_DONE:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,95 +154,92 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
static int libbpf_netlink_send_recv(struct libbpf_nla_req *req,
|
||||||
__u32 flags)
|
__dump_nlmsg_t parse_msg,
|
||||||
|
libbpf_dump_nlmsg_t parse_attr,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
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;
|
__u32 nl_pid = 0;
|
||||||
|
int sock, ret;
|
||||||
|
|
||||||
sock = libbpf_netlink_open(&nl_pid);
|
sock = libbpf_netlink_open(&nl_pid);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
return sock;
|
return sock;
|
||||||
|
|
||||||
memset(&req, 0, sizeof(req));
|
req->nh.nlmsg_pid = 0;
|
||||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
req->nh.nlmsg_seq = time(NULL);
|
||||||
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;
|
|
||||||
|
|
||||||
/* started nested attribute for XDP */
|
if (send(sock, req, req->nh.nlmsg_len, 0) < 0) {
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
|
|
||||||
|
|
||||||
if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
|
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto cleanup;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
cleanup:
|
ret = libbpf_netlink_recv(sock, nl_pid, req->nh.nlmsg_seq,
|
||||||
close(sock);
|
parse_msg, parse_attr, cookie);
|
||||||
|
out:
|
||||||
|
libbpf_netlink_close(sock);
|
||||||
return ret;
|
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;
|
||||||
|
|
||||||
|
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.ifinfo.ifi_family = AF_UNSPEC;
|
||||||
|
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;
|
||||||
|
if (flags) {
|
||||||
|
ret = nlattr_add(&req, IFLA_XDP_FLAGS, &flags, sizeof(flags));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (flags & XDP_FLAGS_REPLACE) {
|
||||||
|
ret = nlattr_add(&req, IFLA_XDP_EXPECTED_FD, &old_fd,
|
||||||
|
sizeof(old_fd));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
nlattr_end_nested(&req, nla);
|
||||||
|
|
||||||
|
return libbpf_netlink_send_recv(&req, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
|
int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
|
||||||
const struct bpf_xdp_set_link_opts *opts)
|
const struct bpf_xdp_set_link_opts *opts)
|
||||||
{
|
{
|
||||||
int old_fd = -1;
|
int old_fd = -1, ret;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, bpf_xdp_set_link_opts))
|
if (!OPTS_VALID(opts, bpf_xdp_set_link_opts))
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
if (OPTS_HAS(opts, old_fd)) {
|
if (OPTS_HAS(opts, old_fd)) {
|
||||||
old_fd = OPTS_GET(opts, old_fd, -1);
|
old_fd = OPTS_GET(opts, old_fd, -1);
|
||||||
flags |= XDP_FLAGS_REPLACE;
|
flags |= XDP_FLAGS_REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd,
|
ret = __bpf_set_link_xdp_fd_replace(ifindex, fd, old_fd, flags);
|
||||||
old_fd,
|
return libbpf_err(ret);
|
||||||
flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||||
{
|
{
|
||||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
|
int ret;
|
||||||
|
|
||||||
|
ret = __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
|
||||||
|
return libbpf_err(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
||||||
@@ -231,6 +251,7 @@ static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
|||||||
|
|
||||||
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
|
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
|
||||||
attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
|
attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
|
||||||
|
|
||||||
if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
|
if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
|
||||||
return -LIBBPF_ERRNO__NLPARSE;
|
return -LIBBPF_ERRNO__NLPARSE;
|
||||||
|
|
||||||
@@ -282,34 +303,33 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
|
||||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
|
|
||||||
|
|
||||||
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||||
size_t info_size, __u32 flags)
|
size_t info_size, __u32 flags)
|
||||||
{
|
{
|
||||||
struct xdp_id_md xdp_id = {};
|
struct xdp_id_md xdp_id = {};
|
||||||
int sock, ret;
|
|
||||||
__u32 nl_pid = 0;
|
|
||||||
__u32 mask;
|
__u32 mask;
|
||||||
|
int ret;
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
if (flags & ~XDP_FLAGS_MASK || !info_size)
|
if (flags & ~XDP_FLAGS_MASK || !info_size)
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
/* Check whether the single {HW,DRV,SKB} mode is set */
|
/* Check whether the single {HW,DRV,SKB} mode is set */
|
||||||
flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
|
flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
|
||||||
mask = flags - 1;
|
mask = flags - 1;
|
||||||
if (flags && flags & mask)
|
if (flags && flags & mask)
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
sock = libbpf_netlink_open(&nl_pid);
|
|
||||||
if (sock < 0)
|
|
||||||
return sock;
|
|
||||||
|
|
||||||
xdp_id.ifindex = ifindex;
|
xdp_id.ifindex = ifindex;
|
||||||
xdp_id.flags = flags;
|
xdp_id.flags = flags;
|
||||||
|
|
||||||
ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
|
ret = libbpf_netlink_send_recv(&req, __dump_link_nlmsg,
|
||||||
|
get_xdp_info, &xdp_id);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
size_t sz = min(info_size, sizeof(xdp_id.info));
|
size_t sz = min(info_size, sizeof(xdp_id.info));
|
||||||
|
|
||||||
@@ -317,8 +337,7 @@ int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
|||||||
memset((void *) info + sz, 0, info_size - sz);
|
memset((void *) info + sz, 0, info_size - sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock);
|
return libbpf_err(ret);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
|
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
|
||||||
@@ -346,27 +365,394 @@ int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
*prog_id = get_xdp_id(&info, flags);
|
*prog_id = get_xdp_id(&info, flags);
|
||||||
|
|
||||||
|
return libbpf_err(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
|
||||||
|
OPTS_GET(hook, ifindex, 0) <= 0)
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
ret = tc_qdisc_create_excl(hook);
|
||||||
|
return libbpf_err(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)
|
||||||
|
{
|
||||||
|
if (!hook || !OPTS_VALID(hook, bpf_tc_hook) ||
|
||||||
|
OPTS_GET(hook, ifindex, 0) <= 0)
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
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)
|
||||||
|
return -errno;
|
||||||
|
if (len >= sizeof(name))
|
||||||
|
return -ENAMETOOLONG;
|
||||||
|
return nlattr_add(req, TCA_BPF_NAME, name, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||||
|
{
|
||||||
|
__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;
|
||||||
|
|
||||||
|
if (!hook || !opts ||
|
||||||
|
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||||
|
!OPTS_VALID(opts, bpf_tc_opts))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
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 ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libbpf_nl_get_link(int sock, unsigned int nl_pid,
|
static int __bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
|
const struct bpf_tc_opts *opts,
|
||||||
|
const bool flush)
|
||||||
{
|
{
|
||||||
struct {
|
__u32 protocol = 0, handle, priority, parent, prog_id, flags;
|
||||||
struct nlmsghdr nlh;
|
int ret, ifindex, attach_point, prog_fd;
|
||||||
struct ifinfomsg ifm;
|
struct libbpf_nla_req req;
|
||||||
} 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);
|
|
||||||
|
|
||||||
req.nlh.nlmsg_seq = seq;
|
if (!hook ||
|
||||||
if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
|
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||||
return -errno;
|
!OPTS_VALID(opts, bpf_tc_opts))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
|
ifindex = OPTS_GET(hook, ifindex, 0);
|
||||||
dump_link_nlmsg, cookie);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_tc_detach(const struct bpf_tc_hook *hook,
|
||||||
|
const struct bpf_tc_opts *opts)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!opts)
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
ret = __bpf_tc_detach(hook, opts, false);
|
||||||
|
return libbpf_err(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bpf_tc_query(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||||
|
{
|
||||||
|
__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;
|
||||||
|
|
||||||
|
if (!hook || !opts ||
|
||||||
|
!OPTS_VALID(hook, bpf_tc_hook) ||
|
||||||
|
!OPTS_VALID(opts, bpf_tc_opts))
|
||||||
|
return libbpf_err(-EINVAL);
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
|
|||||||
int totlen = NLA_ALIGN(nla->nla_len);
|
int totlen = NLA_ALIGN(nla->nla_len);
|
||||||
|
|
||||||
*remaining -= totlen;
|
*remaining -= totlen;
|
||||||
return (struct nlattr *) ((char *) nla + totlen);
|
return (struct nlattr *)((void *)nla + totlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nla_ok(const struct nlattr *nla, int remaining)
|
static int nla_ok(const struct nlattr *nla, int remaining)
|
||||||
|
|||||||
60
src/nlattr.h
60
src/nlattr.h
@@ -10,7 +10,11 @@
|
|||||||
#define __LIBBPF_NLATTR_H
|
#define __LIBBPF_NLATTR_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
/* avoid multiple definition of netlink features */
|
/* avoid multiple definition of netlink features */
|
||||||
#define __LINUX_NETLINK_H
|
#define __LINUX_NETLINK_H
|
||||||
|
|
||||||
@@ -49,6 +53,15 @@ struct libbpf_nla_policy {
|
|||||||
uint16_t maxlen;
|
uint16_t maxlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct libbpf_nla_req {
|
||||||
|
struct nlmsghdr nh;
|
||||||
|
union {
|
||||||
|
struct ifinfomsg ifinfo;
|
||||||
|
struct tcmsg tc;
|
||||||
|
};
|
||||||
|
char buf[128];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup attr
|
* @ingroup attr
|
||||||
* Iterate over a stream of attributes
|
* Iterate over a stream of attributes
|
||||||
@@ -68,7 +81,7 @@ struct libbpf_nla_policy {
|
|||||||
*/
|
*/
|
||||||
static inline void *libbpf_nla_data(const struct nlattr *nla)
|
static inline void *libbpf_nla_data(const struct nlattr *nla)
|
||||||
{
|
{
|
||||||
return (char *) nla + NLA_HDRLEN;
|
return (void *)nla + NLA_HDRLEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
|
static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
|
||||||
@@ -103,4 +116,49 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
|
|||||||
|
|
||||||
int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
|
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 */
|
#endif /* __LIBBPF_NLATTR_H */
|
||||||
|
|||||||
1295
src/relo_core.c
Normal file
1295
src/relo_core.c
Normal file
File diff suppressed because it is too large
Load Diff
100
src/relo_core.h
Normal file
100
src/relo_core.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
/* Copyright (c) 2019 Facebook */
|
||||||
|
|
||||||
|
#ifndef __RELO_CORE_H
|
||||||
|
#define __RELO_CORE_H
|
||||||
|
|
||||||
|
/* bpf_core_relo_kind encodes which aspect of captured field/type/enum value
|
||||||
|
* has to be adjusted by relocations.
|
||||||
|
*/
|
||||||
|
enum bpf_core_relo_kind {
|
||||||
|
BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */
|
||||||
|
BPF_FIELD_BYTE_SIZE = 1, /* field size in bytes */
|
||||||
|
BPF_FIELD_EXISTS = 2, /* field existence in target kernel */
|
||||||
|
BPF_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */
|
||||||
|
BPF_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */
|
||||||
|
BPF_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */
|
||||||
|
BPF_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */
|
||||||
|
BPF_TYPE_ID_TARGET = 7, /* type ID in target kernel */
|
||||||
|
BPF_TYPE_EXISTS = 8, /* type existence in target kernel */
|
||||||
|
BPF_TYPE_SIZE = 9, /* type size in bytes */
|
||||||
|
BPF_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */
|
||||||
|
BPF_ENUMVAL_VALUE = 11, /* enum value integer value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_core_relo checked by the loader
|
||||||
|
*
|
||||||
|
* CO-RE 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
|
||||||
|
* type or field;
|
||||||
|
* - access_str_off - offset into corresponding .BTF string section. String
|
||||||
|
* interpretation depends on specific relocation kind:
|
||||||
|
* - for field-based relocations, string encodes an accessed field using
|
||||||
|
* a sequence of field and array indices, separated by colon (:). It's
|
||||||
|
* conceptually very close to LLVM's getelementptr ([0]) instruction's
|
||||||
|
* arguments for identifying offset to a field.
|
||||||
|
* - for type-based relocations, strings is expected to be just "0";
|
||||||
|
* - for enum value-based relocations, string contains an index of enum
|
||||||
|
* value within its enum type;
|
||||||
|
*
|
||||||
|
* Example to provide a better feel.
|
||||||
|
*
|
||||||
|
* struct sample {
|
||||||
|
* int a;
|
||||||
|
* struct {
|
||||||
|
* int b[10];
|
||||||
|
* };
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct sample *s = ...;
|
||||||
|
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||||
|
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||||
|
* // b is field #0 inside anon struct, accessing elem #5)
|
||||||
|
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||||
|
*
|
||||||
|
* type_id for all relocs in this example will capture BTF type id of
|
||||||
|
* `struct sample`.
|
||||||
|
*
|
||||||
|
* Such relocation is emitted when using __builtin_preserve_access_index()
|
||||||
|
* Clang built-in, passing expression that captures field address, e.g.:
|
||||||
|
*
|
||||||
|
* bpf_probe_read(&dst, sizeof(dst),
|
||||||
|
* __builtin_preserve_access_index(&src->a.b.c));
|
||||||
|
*
|
||||||
|
* In this case Clang will emit field relocation recording necessary data to
|
||||||
|
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
||||||
|
*
|
||||||
|
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
||||||
|
*/
|
||||||
|
struct bpf_core_relo {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 type_id;
|
||||||
|
__u32 access_str_off;
|
||||||
|
enum bpf_core_relo_kind kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_core_cand {
|
||||||
|
const struct btf *btf;
|
||||||
|
const struct btf_type *t;
|
||||||
|
const char *name;
|
||||||
|
__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;
|
||||||
|
};
|
||||||
|
|
||||||
|
int bpf_core_apply_relo_insn(const char *prog_name,
|
||||||
|
struct bpf_insn *insn, int insn_idx,
|
||||||
|
const struct bpf_core_relo *relo, int relo_idx,
|
||||||
|
const struct btf *local_btf,
|
||||||
|
struct bpf_core_cand_list *cands);
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
@@ -69,23 +69,23 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
pr_warn("ringbuf: failed to get map info for fd=%d: %d\n",
|
||||||
map_fd, err);
|
map_fd, err);
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.type != BPF_MAP_TYPE_RINGBUF) {
|
if (info.type != BPF_MAP_TYPE_RINGBUF) {
|
||||||
pr_warn("ringbuf: map fd=%d is not BPF_MAP_TYPE_RINGBUF\n",
|
pr_warn("ringbuf: map fd=%d is not BPF_MAP_TYPE_RINGBUF\n",
|
||||||
map_fd);
|
map_fd);
|
||||||
return -EINVAL;
|
return libbpf_err(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = libbpf_reallocarray(rb->rings, rb->ring_cnt + 1, sizeof(*rb->rings));
|
tmp = libbpf_reallocarray(rb->rings, rb->ring_cnt + 1, sizeof(*rb->rings));
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
return -ENOMEM;
|
return libbpf_err(-ENOMEM);
|
||||||
rb->rings = tmp;
|
rb->rings = tmp;
|
||||||
|
|
||||||
tmp = libbpf_reallocarray(rb->events, rb->ring_cnt + 1, sizeof(*rb->events));
|
tmp = libbpf_reallocarray(rb->events, rb->ring_cnt + 1, sizeof(*rb->events));
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
return -ENOMEM;
|
return libbpf_err(-ENOMEM);
|
||||||
rb->events = tmp;
|
rb->events = tmp;
|
||||||
|
|
||||||
r = &rb->rings[rb->ring_cnt];
|
r = &rb->rings[rb->ring_cnt];
|
||||||
@@ -103,7 +103,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n",
|
||||||
map_fd, err);
|
map_fd, err);
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
}
|
}
|
||||||
r->consumer_pos = tmp;
|
r->consumer_pos = tmp;
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
ringbuf_unmap_ring(rb, r);
|
ringbuf_unmap_ring(rb, r);
|
||||||
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n",
|
||||||
map_fd, err);
|
map_fd, err);
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
}
|
}
|
||||||
r->producer_pos = tmp;
|
r->producer_pos = tmp;
|
||||||
r->data = tmp + rb->page_size;
|
r->data = tmp + rb->page_size;
|
||||||
@@ -133,7 +133,7 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd,
|
|||||||
ringbuf_unmap_ring(rb, r);
|
ringbuf_unmap_ring(rb, r);
|
||||||
pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n",
|
pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n",
|
||||||
map_fd, err);
|
map_fd, err);
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb->ring_cnt++;
|
rb->ring_cnt++;
|
||||||
@@ -165,11 +165,11 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!OPTS_VALID(opts, ring_buffer_opts))
|
if (!OPTS_VALID(opts, ring_buffer_opts))
|
||||||
return NULL;
|
return errno = EINVAL, NULL;
|
||||||
|
|
||||||
rb = calloc(1, sizeof(*rb));
|
rb = calloc(1, sizeof(*rb));
|
||||||
if (!rb)
|
if (!rb)
|
||||||
return NULL;
|
return errno = ENOMEM, NULL;
|
||||||
|
|
||||||
rb->page_size = getpagesize();
|
rb->page_size = getpagesize();
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,
|
|||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
ring_buffer__free(rb);
|
ring_buffer__free(rb);
|
||||||
return NULL;
|
return errno = -err, NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int roundup_len(__u32 len)
|
static inline int roundup_len(__u32 len)
|
||||||
@@ -202,9 +202,11 @@ static inline int roundup_len(__u32 len)
|
|||||||
return (len + 7) / 8 * 8;
|
return (len + 7) / 8 * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ringbuf_process_ring(struct ring* r)
|
static int64_t ringbuf_process_ring(struct ring* r)
|
||||||
{
|
{
|
||||||
int *len_ptr, len, err, cnt = 0;
|
int *len_ptr, len, err;
|
||||||
|
/* 64-bit to avoid overflow in case of extreme application behavior */
|
||||||
|
int64_t cnt = 0;
|
||||||
unsigned long cons_pos, prod_pos;
|
unsigned long cons_pos, prod_pos;
|
||||||
bool got_new_data;
|
bool got_new_data;
|
||||||
void *sample;
|
void *sample;
|
||||||
@@ -227,7 +229,7 @@ static int ringbuf_process_ring(struct ring* r)
|
|||||||
if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) {
|
if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) {
|
||||||
sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ;
|
sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ;
|
||||||
err = r->sample_cb(r->ctx, sample, len);
|
err = r->sample_cb(r->ctx, sample, len);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
/* update consumer pos and bail out */
|
/* update consumer pos and bail out */
|
||||||
smp_store_release(r->consumer_pos,
|
smp_store_release(r->consumer_pos,
|
||||||
cons_pos);
|
cons_pos);
|
||||||
@@ -244,43 +246,53 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Consume available ring buffer(s) data without event polling.
|
/* Consume available ring buffer(s) data without event polling.
|
||||||
* Returns number of records consumed across all registered ring buffers, or
|
* Returns number of records consumed across all registered ring buffers (or
|
||||||
* negative number if any of the callbacks return error.
|
* INT_MAX, whichever is less), or negative number if any of the callbacks
|
||||||
|
* return error.
|
||||||
*/
|
*/
|
||||||
int ring_buffer__consume(struct ring_buffer *rb)
|
int ring_buffer__consume(struct ring_buffer *rb)
|
||||||
{
|
{
|
||||||
int i, err, res = 0;
|
int64_t err, res = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < rb->ring_cnt; i++) {
|
for (i = 0; i < rb->ring_cnt; i++) {
|
||||||
struct ring *ring = &rb->rings[i];
|
struct ring *ring = &rb->rings[i];
|
||||||
|
|
||||||
err = ringbuf_process_ring(ring);
|
err = ringbuf_process_ring(ring);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
res += err;
|
res += err;
|
||||||
}
|
}
|
||||||
|
if (res > INT_MAX)
|
||||||
|
return INT_MAX;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Poll for available data and consume records, if any are available.
|
/* Poll for available data and consume records, if any are available.
|
||||||
* Returns number of records consumed, or negative number, if any of the
|
* Returns number of records consumed (or INT_MAX, whichever is less), or
|
||||||
* registered callbacks returned error.
|
* negative number, if any of the registered callbacks returned error.
|
||||||
*/
|
*/
|
||||||
int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms)
|
int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms)
|
||||||
{
|
{
|
||||||
int i, cnt, err, res = 0;
|
int i, cnt;
|
||||||
|
int64_t err, res = 0;
|
||||||
|
|
||||||
cnt = epoll_wait(rb->epoll_fd, rb->events, rb->ring_cnt, timeout_ms);
|
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++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
__u32 ring_id = rb->events[i].data.fd;
|
__u32 ring_id = rb->events[i].data.fd;
|
||||||
struct ring *ring = &rb->rings[ring_id];
|
struct ring *ring = &rb->rings[ring_id];
|
||||||
|
|
||||||
err = ringbuf_process_ring(ring);
|
err = ringbuf_process_ring(ring);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return libbpf_err(err);
|
||||||
res += err;
|
res += err;
|
||||||
}
|
}
|
||||||
return cnt < 0 ? -errno : res;
|
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) */
|
/* Get an fd that can be used to sleep until data is available in the ring(s) */
|
||||||
|
|||||||
123
src/skel_internal.h
Normal file
123
src/skel_internal.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||||
|
/* Copyright (c) 2021 Facebook */
|
||||||
|
#ifndef __SKEL_INTERNAL_H
|
||||||
|
#define __SKEL_INTERNAL_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
union {
|
||||||
|
/* input for the loader prog */
|
||||||
|
struct {
|
||||||
|
__aligned_u64 initial_value;
|
||||||
|
__u32 max_entries;
|
||||||
|
};
|
||||||
|
/* output of the loader prog */
|
||||||
|
struct {
|
||||||
|
int map_fd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
struct bpf_prog_desc {
|
||||||
|
int prog_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_loader_ctx {
|
||||||
|
size_t sz;
|
||||||
|
__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;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
return syscall(__NR_bpf, cmd, attr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int skel_closenz(int fd)
|
||||||
|
{
|
||||||
|
if (fd > 0)
|
||||||
|
return close(fd);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
map_fd = bpf_create_map_name(BPF_MAP_TYPE_ARRAY, "__loader.map", 4,
|
||||||
|
opts->data_sz, 1, 0);
|
||||||
|
if (map_fd < 0) {
|
||||||
|
opts->errstr = "failed to create loader map";
|
||||||
|
err = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_map_update_elem(map_fd, &key, opts->data, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
opts->errstr = "failed to update loader map";
|
||||||
|
err = -errno;
|
||||||
|
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;
|
||||||
|
prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||||
|
if (prog_fd < 0) {
|
||||||
|
opts->errstr = "failed to load loader prog";
|
||||||
|
err = -errno;
|
||||||
|
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)
|
||||||
|
err = -errno;
|
||||||
|
else
|
||||||
|
err = (int)attr.test.retval;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
err = 0;
|
||||||
|
out:
|
||||||
|
if (map_fd >= 0)
|
||||||
|
close(map_fd);
|
||||||
|
if (prog_fd >= 0)
|
||||||
|
close(prog_fd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
176
src/strset.c
Normal file
176
src/strset.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
Normal file
21
src/strset.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/* 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 */
|
||||||
412
src/xsk.c
412
src/xsk.c
@@ -28,6 +28,7 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <linux/if_link.h>
|
||||||
|
|
||||||
#include "bpf.h"
|
#include "bpf.h"
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
@@ -46,6 +47,11 @@
|
|||||||
#define PF_XDP AF_XDP
|
#define PF_XDP AF_XDP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum xsk_prog {
|
||||||
|
XSK_PROG_FALLBACK,
|
||||||
|
XSK_PROG_REDIRECT_FLAGS,
|
||||||
|
};
|
||||||
|
|
||||||
struct xsk_umem {
|
struct xsk_umem {
|
||||||
struct xsk_ring_prod *fill_save;
|
struct xsk_ring_prod *fill_save;
|
||||||
struct xsk_ring_cons *comp_save;
|
struct xsk_ring_cons *comp_save;
|
||||||
@@ -54,6 +60,8 @@ struct xsk_umem {
|
|||||||
int fd;
|
int fd;
|
||||||
int refcount;
|
int refcount;
|
||||||
struct list_head ctx_list;
|
struct list_head ctx_list;
|
||||||
|
bool rx_ring_setup_done;
|
||||||
|
bool tx_ring_setup_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xsk_ctx {
|
struct xsk_ctx {
|
||||||
@@ -65,8 +73,10 @@ struct xsk_ctx {
|
|||||||
int ifindex;
|
int ifindex;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int prog_fd;
|
int prog_fd;
|
||||||
|
int link_fd;
|
||||||
int xsks_map_fd;
|
int xsks_map_fd;
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
|
bool has_bpf_link;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xsk_socket {
|
struct xsk_socket {
|
||||||
@@ -351,14 +361,62 @@ int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
|
|||||||
COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
|
COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
|
||||||
DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
|
DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
|
||||||
|
|
||||||
|
static enum xsk_prog get_xsk_prog(void)
|
||||||
|
{
|
||||||
|
enum xsk_prog detected = XSK_PROG_FALLBACK;
|
||||||
|
struct bpf_load_program_attr prog_attr;
|
||||||
|
struct bpf_create_map_attr map_attr;
|
||||||
|
__u32 size_out, retval, duration;
|
||||||
|
char data_in = 0, data_out;
|
||||||
|
struct bpf_insn insns[] = {
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_3, XDP_PASS),
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
};
|
||||||
|
int prog_fd, map_fd, ret;
|
||||||
|
|
||||||
|
memset(&map_attr, 0, sizeof(map_attr));
|
||||||
|
map_attr.map_type = BPF_MAP_TYPE_XSKMAP;
|
||||||
|
map_attr.key_size = sizeof(int);
|
||||||
|
map_attr.value_size = sizeof(int);
|
||||||
|
map_attr.max_entries = 1;
|
||||||
|
|
||||||
|
map_fd = bpf_create_map_xattr(&map_attr);
|
||||||
|
if (map_fd < 0)
|
||||||
|
return detected;
|
||||||
|
|
||||||
|
insns[0].imm = map_fd;
|
||||||
|
|
||||||
|
memset(&prog_attr, 0, sizeof(prog_attr));
|
||||||
|
prog_attr.prog_type = BPF_PROG_TYPE_XDP;
|
||||||
|
prog_attr.insns = insns;
|
||||||
|
prog_attr.insns_cnt = ARRAY_SIZE(insns);
|
||||||
|
prog_attr.license = "GPL";
|
||||||
|
|
||||||
|
prog_fd = bpf_load_program_xattr(&prog_attr, NULL, 0);
|
||||||
|
if (prog_fd < 0) {
|
||||||
|
close(map_fd);
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bpf_prog_test_run(prog_fd, 0, &data_in, 1, &data_out, &size_out, &retval, &duration);
|
||||||
|
if (!ret && retval == XDP_PASS)
|
||||||
|
detected = XSK_PROG_REDIRECT_FLAGS;
|
||||||
|
close(prog_fd);
|
||||||
|
close(map_fd);
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
static const int log_buf_size = 16 * 1024;
|
static const int log_buf_size = 16 * 1024;
|
||||||
struct xsk_ctx *ctx = xsk->ctx;
|
struct xsk_ctx *ctx = xsk->ctx;
|
||||||
char log_buf[log_buf_size];
|
char log_buf[log_buf_size];
|
||||||
int err, prog_fd;
|
int prog_fd;
|
||||||
|
|
||||||
/* This is the C-program:
|
/* This is the fallback C-program:
|
||||||
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
||||||
* {
|
* {
|
||||||
* int ret, index = ctx->rx_queue_index;
|
* int ret, index = ctx->rx_queue_index;
|
||||||
@@ -414,9 +472,31 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
/* The jumps are to this instruction */
|
/* The jumps are to this instruction */
|
||||||
BPF_EXIT_INSN(),
|
BPF_EXIT_INSN(),
|
||||||
};
|
};
|
||||||
size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
|
|
||||||
|
|
||||||
prog_fd = bpf_load_program(BPF_PROG_TYPE_XDP, prog, insns_cnt,
|
/* This is the post-5.3 kernel C-program:
|
||||||
|
* SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
|
||||||
|
* {
|
||||||
|
* return bpf_redirect_map(&xsks_map, ctx->rx_queue_index, XDP_PASS);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
struct bpf_insn prog_redirect_flags[] = {
|
||||||
|
/* r2 = *(u32 *)(r1 + 16) */
|
||||||
|
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 16),
|
||||||
|
/* r1 = xskmap[] */
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, ctx->xsks_map_fd),
|
||||||
|
/* r3 = XDP_PASS */
|
||||||
|
BPF_MOV64_IMM(BPF_REG_3, 2),
|
||||||
|
/* call bpf_redirect_map */
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
};
|
||||||
|
size_t insns_cnt[] = {sizeof(prog) / sizeof(struct bpf_insn),
|
||||||
|
sizeof(prog_redirect_flags) / sizeof(struct bpf_insn),
|
||||||
|
};
|
||||||
|
struct bpf_insn *progs[] = {prog, prog_redirect_flags};
|
||||||
|
enum xsk_prog option = get_xsk_prog();
|
||||||
|
|
||||||
|
prog_fd = bpf_load_program(BPF_PROG_TYPE_XDP, progs[option], insns_cnt[option],
|
||||||
"LGPL-2.1 or BSD-2-Clause", 0, log_buf,
|
"LGPL-2.1 or BSD-2-Clause", 0, log_buf,
|
||||||
log_buf_size);
|
log_buf_size);
|
||||||
if (prog_fd < 0) {
|
if (prog_fd < 0) {
|
||||||
@@ -424,14 +504,41 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
|||||||
return prog_fd;
|
return prog_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bpf_set_link_xdp_fd(xsk->ctx->ifindex, prog_fd,
|
ctx->prog_fd = prog_fd;
|
||||||
xsk->config.xdp_flags);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xsk_create_bpf_link(struct xsk_socket *xsk)
|
||||||
|
{
|
||||||
|
DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
|
||||||
|
struct xsk_ctx *ctx = xsk->ctx;
|
||||||
|
__u32 prog_id = 0;
|
||||||
|
int link_fd;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bpf_get_link_xdp_id(ctx->ifindex, &prog_id, xsk->config.xdp_flags);
|
||||||
if (err) {
|
if (err) {
|
||||||
close(prog_fd);
|
pr_warn("getting XDP prog id failed\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->prog_fd = prog_fd;
|
/* if there's a netlink-based XDP prog loaded on interface, bail out
|
||||||
|
* and ask user to do the removal by himself
|
||||||
|
*/
|
||||||
|
if (prog_id) {
|
||||||
|
pr_warn("Netlink-based XDP prog detected, please unload it in order to launch AF_XDP prog\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.flags = xsk->config.xdp_flags & ~(XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_REPLACE);
|
||||||
|
|
||||||
|
link_fd = bpf_link_create(ctx->prog_fd, ctx->ifindex, BPF_XDP, &opts);
|
||||||
|
if (link_fd < 0) {
|
||||||
|
pr_warn("bpf_link_create failed: %s\n", strerror(errno));
|
||||||
|
return link_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->link_fd = link_fd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +549,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
|
|||||||
struct ifreq ifr = {};
|
struct ifreq ifr = {};
|
||||||
int fd, err, ret;
|
int fd, err, ret;
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@@ -535,21 +642,21 @@ static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
memset(&map_info, 0, map_len);
|
||||||
err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len);
|
err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len);
|
||||||
if (err) {
|
if (err) {
|
||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(map_info.name, "xsks_map")) {
|
if (!strncmp(map_info.name, "xsks_map", sizeof(map_info.name))) {
|
||||||
ctx->xsks_map_fd = fd;
|
ctx->xsks_map_fd = fd;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
|
||||||
if (ctx->xsks_map_fd == -1)
|
if (ctx->xsks_map_fd == -1)
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
|
|
||||||
@@ -566,6 +673,98 @@ static int xsk_set_bpf_maps(struct xsk_socket *xsk)
|
|||||||
&xsk->fd, 0);
|
&xsk->fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xsk_link_lookup(int ifindex, __u32 *prog_id, int *link_fd)
|
||||||
|
{
|
||||||
|
struct bpf_link_info link_info;
|
||||||
|
__u32 link_len;
|
||||||
|
__u32 id = 0;
|
||||||
|
int err;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
err = bpf_link_get_next_id(id, &id);
|
||||||
|
if (err) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
err = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pr_warn("can't get next link: %s\n", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = bpf_link_get_fd_by_id(id);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
continue;
|
||||||
|
pr_warn("can't get link by id (%u): %s\n", id, strerror(errno));
|
||||||
|
err = -errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
link_len = sizeof(struct bpf_link_info);
|
||||||
|
memset(&link_info, 0, link_len);
|
||||||
|
err = bpf_obj_get_info_by_fd(fd, &link_info, &link_len);
|
||||||
|
if (err) {
|
||||||
|
pr_warn("can't get link info: %s\n", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (link_info.type == BPF_LINK_TYPE_XDP) {
|
||||||
|
if (link_info.xdp.ifindex == ifindex) {
|
||||||
|
*link_fd = fd;
|
||||||
|
if (prog_id)
|
||||||
|
*prog_id = link_info.prog_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xsk_probe_bpf_link(void)
|
||||||
|
{
|
||||||
|
DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts,
|
||||||
|
.flags = XDP_FLAGS_SKB_MODE);
|
||||||
|
struct bpf_load_program_attr prog_attr;
|
||||||
|
struct bpf_insn insns[2] = {
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
|
||||||
|
BPF_EXIT_INSN()
|
||||||
|
};
|
||||||
|
int prog_fd, link_fd = -1;
|
||||||
|
int ifindex_lo = 1;
|
||||||
|
bool ret = false;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xsk_link_lookup(ifindex_lo, NULL, &link_fd);
|
||||||
|
if (err)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (link_fd >= 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
memset(&prog_attr, 0, sizeof(prog_attr));
|
||||||
|
prog_attr.prog_type = BPF_PROG_TYPE_XDP;
|
||||||
|
prog_attr.insns = insns;
|
||||||
|
prog_attr.insns_cnt = ARRAY_SIZE(insns);
|
||||||
|
prog_attr.license = "GPL";
|
||||||
|
|
||||||
|
prog_fd = bpf_load_program_xattr(&prog_attr, NULL, 0);
|
||||||
|
if (prog_fd < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
link_fd = bpf_link_create(prog_fd, ifindex_lo, BPF_XDP, &opts);
|
||||||
|
close(prog_fd);
|
||||||
|
|
||||||
|
if (link_fd >= 0) {
|
||||||
|
ret = true;
|
||||||
|
close(link_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk)
|
static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk)
|
||||||
{
|
{
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
@@ -587,65 +786,109 @@ static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk)
|
|||||||
ctx->ifname[IFNAMSIZ - 1] = 0;
|
ctx->ifname[IFNAMSIZ - 1] = 0;
|
||||||
|
|
||||||
xsk->ctx = ctx;
|
xsk->ctx = ctx;
|
||||||
|
xsk->ctx->has_bpf_link = xsk_probe_bpf_link();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __xsk_setup_xdp_prog(struct xsk_socket *_xdp,
|
static int xsk_init_xdp_res(struct xsk_socket *xsk,
|
||||||
int *xsks_map_fd)
|
int *xsks_map_fd)
|
||||||
|
{
|
||||||
|
struct xsk_ctx *ctx = xsk->ctx;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xsk_create_bpf_maps(xsk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = xsk_load_xdp_prog(xsk);
|
||||||
|
if (err)
|
||||||
|
goto err_load_xdp_prog;
|
||||||
|
|
||||||
|
if (ctx->has_bpf_link)
|
||||||
|
err = xsk_create_bpf_link(xsk);
|
||||||
|
else
|
||||||
|
err = bpf_set_link_xdp_fd(xsk->ctx->ifindex, ctx->prog_fd,
|
||||||
|
xsk->config.xdp_flags);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto err_attach_xdp_prog;
|
||||||
|
|
||||||
|
if (!xsk->rx)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = xsk_set_bpf_maps(xsk);
|
||||||
|
if (err)
|
||||||
|
goto err_set_bpf_maps;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err_set_bpf_maps:
|
||||||
|
if (ctx->has_bpf_link)
|
||||||
|
close(ctx->link_fd);
|
||||||
|
else
|
||||||
|
bpf_set_link_xdp_fd(ctx->ifindex, -1, 0);
|
||||||
|
err_attach_xdp_prog:
|
||||||
|
close(ctx->prog_fd);
|
||||||
|
err_load_xdp_prog:
|
||||||
|
xsk_delete_bpf_maps(xsk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xsk_lookup_xdp_res(struct xsk_socket *xsk, int *xsks_map_fd, int prog_id)
|
||||||
|
{
|
||||||
|
struct xsk_ctx *ctx = xsk->ctx;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ctx->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
||||||
|
if (ctx->prog_fd < 0) {
|
||||||
|
err = -errno;
|
||||||
|
goto err_prog_fd;
|
||||||
|
}
|
||||||
|
err = xsk_lookup_bpf_maps(xsk);
|
||||||
|
if (err)
|
||||||
|
goto err_lookup_maps;
|
||||||
|
|
||||||
|
if (!xsk->rx)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = xsk_set_bpf_maps(xsk);
|
||||||
|
if (err)
|
||||||
|
goto err_set_maps;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err_set_maps:
|
||||||
|
close(ctx->xsks_map_fd);
|
||||||
|
err_lookup_maps:
|
||||||
|
close(ctx->prog_fd);
|
||||||
|
err_prog_fd:
|
||||||
|
if (ctx->has_bpf_link)
|
||||||
|
close(ctx->link_fd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __xsk_setup_xdp_prog(struct xsk_socket *_xdp, int *xsks_map_fd)
|
||||||
{
|
{
|
||||||
struct xsk_socket *xsk = _xdp;
|
struct xsk_socket *xsk = _xdp;
|
||||||
struct xsk_ctx *ctx = xsk->ctx;
|
struct xsk_ctx *ctx = xsk->ctx;
|
||||||
__u32 prog_id = 0;
|
__u32 prog_id = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bpf_get_link_xdp_id(ctx->ifindex, &prog_id,
|
if (ctx->has_bpf_link)
|
||||||
xsk->config.xdp_flags);
|
err = xsk_link_lookup(ctx->ifindex, &prog_id, &ctx->link_fd);
|
||||||
|
else
|
||||||
|
err = bpf_get_link_xdp_id(ctx->ifindex, &prog_id, xsk->config.xdp_flags);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!prog_id) {
|
err = !prog_id ? xsk_init_xdp_res(xsk, xsks_map_fd) :
|
||||||
err = xsk_create_bpf_maps(xsk);
|
xsk_lookup_xdp_res(xsk, xsks_map_fd, prog_id);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = xsk_load_xdp_prog(xsk);
|
if (!err && xsks_map_fd)
|
||||||
if (err) {
|
|
||||||
goto err_load_xdp_prog;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx->prog_fd = bpf_prog_get_fd_by_id(prog_id);
|
|
||||||
if (ctx->prog_fd < 0)
|
|
||||||
return -errno;
|
|
||||||
err = xsk_lookup_bpf_maps(xsk);
|
|
||||||
if (err) {
|
|
||||||
close(ctx->prog_fd);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xsk->rx) {
|
|
||||||
err = xsk_set_bpf_maps(xsk);
|
|
||||||
if (err) {
|
|
||||||
if (!prog_id) {
|
|
||||||
goto err_set_bpf_maps;
|
|
||||||
} else {
|
|
||||||
close(ctx->prog_fd);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (xsks_map_fd)
|
|
||||||
*xsks_map_fd = ctx->xsks_map_fd;
|
*xsks_map_fd = ctx->xsks_map_fd;
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_set_bpf_maps:
|
|
||||||
close(ctx->prog_fd);
|
|
||||||
bpf_set_link_xdp_fd(ctx->ifindex, -1, 0);
|
|
||||||
err_load_xdp_prog:
|
|
||||||
xsk_delete_bpf_maps(xsk);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,26 +910,30 @@ static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xsk_put_ctx(struct xsk_ctx *ctx)
|
static void xsk_put_ctx(struct xsk_ctx *ctx, bool unmap)
|
||||||
{
|
{
|
||||||
struct xsk_umem *umem = ctx->umem;
|
struct xsk_umem *umem = ctx->umem;
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (--ctx->refcount == 0) {
|
if (--ctx->refcount)
|
||||||
err = xsk_get_mmap_offsets(umem->fd, &off);
|
return;
|
||||||
if (!err) {
|
|
||||||
munmap(ctx->fill->ring - off.fr.desc,
|
|
||||||
off.fr.desc + umem->config.fill_size *
|
|
||||||
sizeof(__u64));
|
|
||||||
munmap(ctx->comp->ring - off.cr.desc,
|
|
||||||
off.cr.desc + umem->config.comp_size *
|
|
||||||
sizeof(__u64));
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del(&ctx->list);
|
if (!unmap)
|
||||||
free(ctx);
|
goto out_free;
|
||||||
}
|
|
||||||
|
err = xsk_get_mmap_offsets(umem->fd, &off);
|
||||||
|
if (err)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size *
|
||||||
|
sizeof(__u64));
|
||||||
|
munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size *
|
||||||
|
sizeof(__u64));
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
list_del(&ctx->list);
|
||||||
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
|
static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
|
||||||
@@ -721,8 +968,6 @@ static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
|
|||||||
memcpy(ctx->ifname, ifname, IFNAMSIZ - 1);
|
memcpy(ctx->ifname, ifname, IFNAMSIZ - 1);
|
||||||
ctx->ifname[IFNAMSIZ - 1] = '\0';
|
ctx->ifname[IFNAMSIZ - 1] = '\0';
|
||||||
|
|
||||||
umem->fill_save = NULL;
|
|
||||||
umem->comp_save = NULL;
|
|
||||||
ctx->fill = fill;
|
ctx->fill = fill;
|
||||||
ctx->comp = comp;
|
ctx->comp = comp;
|
||||||
list_add(&ctx->list, &umem->ctx_list);
|
list_add(&ctx->list, &umem->ctx_list);
|
||||||
@@ -772,6 +1017,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
struct xsk_ring_cons *comp,
|
struct xsk_ring_cons *comp,
|
||||||
const struct xsk_socket_config *usr_config)
|
const struct xsk_socket_config *usr_config)
|
||||||
{
|
{
|
||||||
|
bool unmap, rx_setup_done = false, tx_setup_done = false;
|
||||||
void *rx_map = NULL, *tx_map = NULL;
|
void *rx_map = NULL, *tx_map = NULL;
|
||||||
struct sockaddr_xdp sxdp = {};
|
struct sockaddr_xdp sxdp = {};
|
||||||
struct xdp_mmap_offsets off;
|
struct xdp_mmap_offsets off;
|
||||||
@@ -782,6 +1028,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
if (!umem || !xsk_ptr || !(rx || tx))
|
if (!umem || !xsk_ptr || !(rx || tx))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
unmap = umem->fill_save != fill;
|
||||||
|
|
||||||
xsk = calloc(1, sizeof(*xsk));
|
xsk = calloc(1, sizeof(*xsk));
|
||||||
if (!xsk)
|
if (!xsk)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -805,6 +1053,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xsk->fd = umem->fd;
|
xsk->fd = umem->fd;
|
||||||
|
rx_setup_done = umem->rx_ring_setup_done;
|
||||||
|
tx_setup_done = umem->tx_ring_setup_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = xsk_get_ctx(umem, ifindex, queue_id);
|
ctx = xsk_get_ctx(umem, ifindex, queue_id);
|
||||||
@@ -822,8 +1072,9 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
xsk->ctx = ctx;
|
xsk->ctx = ctx;
|
||||||
|
xsk->ctx->has_bpf_link = xsk_probe_bpf_link();
|
||||||
|
|
||||||
if (rx) {
|
if (rx && !rx_setup_done) {
|
||||||
err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
|
err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
|
||||||
&xsk->config.rx_size,
|
&xsk->config.rx_size,
|
||||||
sizeof(xsk->config.rx_size));
|
sizeof(xsk->config.rx_size));
|
||||||
@@ -831,8 +1082,10 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_put_ctx;
|
goto out_put_ctx;
|
||||||
}
|
}
|
||||||
|
if (xsk->fd == umem->fd)
|
||||||
|
umem->rx_ring_setup_done = true;
|
||||||
}
|
}
|
||||||
if (tx) {
|
if (tx && !tx_setup_done) {
|
||||||
err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
|
err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
|
||||||
&xsk->config.tx_size,
|
&xsk->config.tx_size,
|
||||||
sizeof(xsk->config.tx_size));
|
sizeof(xsk->config.tx_size));
|
||||||
@@ -840,6 +1093,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
err = -errno;
|
err = -errno;
|
||||||
goto out_put_ctx;
|
goto out_put_ctx;
|
||||||
}
|
}
|
||||||
|
if (xsk->fd == umem->fd)
|
||||||
|
umem->tx_ring_setup_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
||||||
@@ -918,6 +1173,8 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*xsk_ptr = xsk;
|
*xsk_ptr = xsk;
|
||||||
|
umem->fill_save = NULL;
|
||||||
|
umem->comp_save = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_mmap_tx:
|
out_mmap_tx:
|
||||||
@@ -929,7 +1186,7 @@ out_mmap_rx:
|
|||||||
munmap(rx_map, off.rx.desc +
|
munmap(rx_map, off.rx.desc +
|
||||||
xsk->config.rx_size * sizeof(struct xdp_desc));
|
xsk->config.rx_size * sizeof(struct xdp_desc));
|
||||||
out_put_ctx:
|
out_put_ctx:
|
||||||
xsk_put_ctx(ctx);
|
xsk_put_ctx(ctx, unmap);
|
||||||
out_socket:
|
out_socket:
|
||||||
if (--umem->refcount)
|
if (--umem->refcount)
|
||||||
close(xsk->fd);
|
close(xsk->fd);
|
||||||
@@ -943,6 +1200,9 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
|||||||
struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
|
struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
|
||||||
const struct xsk_socket_config *usr_config)
|
const struct xsk_socket_config *usr_config)
|
||||||
{
|
{
|
||||||
|
if (!umem)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem,
|
return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem,
|
||||||
rx, tx, umem->fill_save,
|
rx, tx, umem->fill_save,
|
||||||
umem->comp_save, usr_config);
|
umem->comp_save, usr_config);
|
||||||
@@ -978,6 +1238,8 @@ void xsk_socket__delete(struct xsk_socket *xsk)
|
|||||||
if (ctx->prog_fd != -1) {
|
if (ctx->prog_fd != -1) {
|
||||||
xsk_delete_bpf_maps(xsk);
|
xsk_delete_bpf_maps(xsk);
|
||||||
close(ctx->prog_fd);
|
close(ctx->prog_fd);
|
||||||
|
if (ctx->has_bpf_link)
|
||||||
|
close(ctx->link_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
err = xsk_get_mmap_offsets(xsk->fd, &off);
|
||||||
@@ -992,7 +1254,7 @@ void xsk_socket__delete(struct xsk_socket *xsk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xsk_put_ctx(ctx);
|
xsk_put_ctx(ctx, true);
|
||||||
|
|
||||||
umem->refcount--;
|
umem->refcount--;
|
||||||
/* Do not close an fd that also has an associated umem connected
|
/* Do not close an fd that also has an associated umem connected
|
||||||
|
|||||||
87
src/xsk.h
87
src/xsk.h
@@ -3,7 +3,8 @@
|
|||||||
/*
|
/*
|
||||||
* AF_XDP user-space access library.
|
* AF_XDP user-space access library.
|
||||||
*
|
*
|
||||||
* Copyright(c) 2018 - 2019 Intel Corporation.
|
* Copyright (c) 2018 - 2019 Intel Corporation.
|
||||||
|
* Copyright (c) 2019 Facebook
|
||||||
*
|
*
|
||||||
* Author(s): Magnus Karlsson <magnus.karlsson@intel.com>
|
* Author(s): Magnus Karlsson <magnus.karlsson@intel.com>
|
||||||
*/
|
*/
|
||||||
@@ -13,15 +14,80 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <linux/if_xdp.h>
|
#include <linux/if_xdp.h>
|
||||||
|
|
||||||
#include "libbpf.h"
|
#include "libbpf.h"
|
||||||
#include "libbpf_util.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 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. */
|
/* Do not access these members directly. Use the functions below. */
|
||||||
#define DEFINE_XSK_RING(name) \
|
#define DEFINE_XSK_RING(name) \
|
||||||
struct name { \
|
struct name { \
|
||||||
@@ -96,7 +162,8 @@ static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
|||||||
* this function. Without this optimization it whould have been
|
* this function. Without this optimization it whould have been
|
||||||
* free_entries = r->cached_prod - r->cached_cons + r->size.
|
* free_entries = r->cached_prod - r->cached_cons + r->size.
|
||||||
*/
|
*/
|
||||||
r->cached_cons = *r->consumer + r->size;
|
r->cached_cons = libbpf_smp_load_acquire(r->consumer);
|
||||||
|
r->cached_cons += r->size;
|
||||||
|
|
||||||
return r->cached_cons - r->cached_prod;
|
return r->cached_cons - r->cached_prod;
|
||||||
}
|
}
|
||||||
@@ -106,7 +173,7 @@ static inline __u32 xsk_cons_nb_avail(struct xsk_ring_cons *r, __u32 nb)
|
|||||||
__u32 entries = r->cached_prod - r->cached_cons;
|
__u32 entries = r->cached_prod - r->cached_cons;
|
||||||
|
|
||||||
if (entries == 0) {
|
if (entries == 0) {
|
||||||
r->cached_prod = *r->producer;
|
r->cached_prod = libbpf_smp_load_acquire(r->producer);
|
||||||
entries = r->cached_prod - r->cached_cons;
|
entries = r->cached_prod - r->cached_cons;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +196,7 @@ static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, __u32 nb)
|
|||||||
/* Make sure everything has been written to the ring before indicating
|
/* Make sure everything has been written to the ring before indicating
|
||||||
* this to the kernel by writing the producer pointer.
|
* this to the kernel by writing the producer pointer.
|
||||||
*/
|
*/
|
||||||
libbpf_smp_wmb();
|
libbpf_smp_store_release(prod->producer, *prod->producer + nb);
|
||||||
|
|
||||||
*prod->producer += nb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx)
|
static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx)
|
||||||
@@ -139,11 +204,6 @@ static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __
|
|||||||
__u32 entries = xsk_cons_nb_avail(cons, nb);
|
__u32 entries = xsk_cons_nb_avail(cons, nb);
|
||||||
|
|
||||||
if (entries > 0) {
|
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;
|
*idx = cons->cached_cons;
|
||||||
cons->cached_cons += entries;
|
cons->cached_cons += entries;
|
||||||
}
|
}
|
||||||
@@ -161,9 +221,8 @@ static inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, __u32 nb)
|
|||||||
/* Make sure data has been read before indicating we are done
|
/* Make sure data has been read before indicating we are done
|
||||||
* with the entries by updating the consumer pointer.
|
* with the entries by updating the consumer pointer.
|
||||||
*/
|
*/
|
||||||
libbpf_smp_rwmb();
|
libbpf_smp_store_release(cons->consumer, *cons->consumer + nb);
|
||||||
|
|
||||||
*cons->consumer += nb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
|
|||||||
ENV_VARS="${ENV_VARS:-}"
|
ENV_VARS="${ENV_VARS:-}"
|
||||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||||
ADDITIONAL_DEPS=(clang pkg-config gcc-8)
|
ADDITIONAL_DEPS=(clang pkg-config gcc-10)
|
||||||
CFLAGS="-g -O2 -Werror -Wall"
|
CFLAGS="-g -O2 -Werror -Wall"
|
||||||
|
|
||||||
function info() {
|
function info() {
|
||||||
@@ -18,10 +18,10 @@ function error() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function docker_exec() {
|
function docker_exec() {
|
||||||
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
docker exec $ENV_VARS $CONT_NAME "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
set -e
|
set -eu
|
||||||
|
|
||||||
source "$(dirname $0)/travis_wait.bash"
|
source "$(dirname $0)/travis_wait.bash"
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ for phase in "${PHASES[@]}"; do
|
|||||||
info "Setup phase"
|
info "Setup phase"
|
||||||
info "Using Debian $DEBIAN_RELEASE"
|
info "Using Debian $DEBIAN_RELEASE"
|
||||||
|
|
||||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
|
||||||
docker --version
|
docker --version
|
||||||
|
|
||||||
docker pull debian:$DEBIAN_RELEASE
|
docker pull debian:$DEBIAN_RELEASE
|
||||||
@@ -39,19 +38,24 @@ for phase in "${PHASES[@]}"; do
|
|||||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||||
-w /build --privileged=true --name $CONT_NAME \
|
-w /build --privileged=true --name $CONT_NAME \
|
||||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||||
|
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 bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||||
docker_exec apt-get -y update
|
docker_exec apt-get -y update
|
||||||
docker_exec apt-get -y build-dep libelf-dev
|
docker_exec apt-get -y install aptitude
|
||||||
docker_exec apt-get -y install libelf-dev
|
docker_exec aptitude -y build-dep libelf-dev
|
||||||
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
docker_exec aptitude -y install libelf-dev
|
||||||
|
docker_exec aptitude -y install "${ADDITIONAL_DEPS[@]}"
|
||||||
|
echo -e "::endgroup::"
|
||||||
;;
|
;;
|
||||||
RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
RUN|RUN_CLANG|RUN_GCC10|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC10_ASAN)
|
||||||
|
CC="cc"
|
||||||
if [[ "$phase" = *"CLANG"* ]]; then
|
if [[ "$phase" = *"CLANG"* ]]; then
|
||||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||||
CC="clang"
|
CC="clang"
|
||||||
elif [[ "$phase" = *"GCC8"* ]]; then
|
elif [[ "$phase" = *"GCC10"* ]]; then
|
||||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
ENV_VARS="-e CC=gcc-10 -e CXX=g++-10"
|
||||||
CC="gcc-8"
|
CC="gcc-10"
|
||||||
|
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
||||||
else
|
else
|
||||||
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
CFLAGS="${CFLAGS} -Wno-stringop-truncation"
|
||||||
fi
|
fi
|
||||||
@@ -59,9 +63,9 @@ for phase in "${PHASES[@]}"; do
|
|||||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||||
fi
|
fi
|
||||||
docker_exec mkdir build install
|
docker_exec mkdir build install
|
||||||
docker_exec ${CC:-cc} --version
|
docker_exec ${CC} --version
|
||||||
info "build"
|
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:"
|
info "ldd build/libbpf.so:"
|
||||||
docker_exec ldd build/libbpf.so
|
docker_exec ldd build/libbpf.so
|
||||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||||
@@ -70,7 +74,8 @@ for phase in "${PHASES[@]}"; do
|
|||||||
fi
|
fi
|
||||||
info "install"
|
info "install"
|
||||||
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||||
docker_exec rm -rf build install
|
info "link binary"
|
||||||
|
docker_exec bash -c "CFLAGS=\"${CFLAGS}\" ./travis-ci/managers/test_compile.sh"
|
||||||
;;
|
;;
|
||||||
CLEANUP)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
|
|||||||
14
travis-ci/managers/test_compile.sh
Executable file
14
travis-ci/managers/test_compile.sh
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/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,20 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -eux
|
||||||
set -x
|
|
||||||
|
|
||||||
RELEASE="bionic"
|
RELEASE="focal"
|
||||||
|
|
||||||
echo "deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse" >>/etc/apt/sources.list
|
|
||||||
|
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y build-dep libelf-dev
|
apt-get install -y pkg-config
|
||||||
apt-get install -y libelf-dev pkg-config
|
|
||||||
|
|
||||||
source "$(dirname $0)/travis_wait.bash"
|
source "$(dirname $0)/travis_wait.bash"
|
||||||
|
|
||||||
cd $REPO_ROOT
|
cd $REPO_ROOT
|
||||||
|
|
||||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined -Wno-stringop-truncation"
|
||||||
mkdir build install
|
mkdir build install
|
||||||
cc --version
|
cc --version
|
||||||
make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||||
@@ -24,4 +20,4 @@ if ! ldd build/libbpf.so | grep -q libelf; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||||
rm -rf build install
|
CFLAGS=${CFLAGS} $(dirname $0)/test_compile.sh
|
||||||
|
|||||||
@@ -4,18 +4,22 @@ set -eu
|
|||||||
|
|
||||||
source $(cd $(dirname $0) && pwd)/helpers.sh
|
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||||
|
|
||||||
travis_fold start build_pahole "Building pahole"
|
|
||||||
|
|
||||||
CWD=$(pwd)
|
CWD=$(pwd)
|
||||||
REPO_PATH=$1
|
REPO_PATH=$1
|
||||||
PAHOLE_ORIGIN=https://git.kernel.org/pub/scm/devel/pahole/pahole.git
|
PAHOLE_ORIGIN=${PAHOLE_ORIGIN:-https://git.kernel.org/pub/scm/devel/pahole/pahole.git}
|
||||||
|
PAHOLE_BRANCH=${PAHOLE_BRANCH:-master}
|
||||||
|
|
||||||
|
travis_fold start build_pahole "Building pahole ${PAHOLE_ORIGIN} ${PAHOLE_BRANCH}"
|
||||||
|
|
||||||
mkdir -p ${REPO_PATH}
|
mkdir -p ${REPO_PATH}
|
||||||
cd ${REPO_PATH}
|
cd ${REPO_PATH}
|
||||||
git init
|
git init
|
||||||
git remote add origin ${PAHOLE_ORIGIN}
|
git remote add origin ${PAHOLE_ORIGIN}
|
||||||
git fetch origin
|
git fetch origin
|
||||||
git checkout master
|
git checkout ${PAHOLE_BRANCH}
|
||||||
|
|
||||||
|
# temporary work-around to bump pahole to 1.22 before it is officially released
|
||||||
|
sed -i 's/DDWARVES_MINOR_VERSION=21/DDWARVES_MINOR_VERSION=22/' CMakeLists.txt
|
||||||
|
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ source $(cd $(dirname $0) && pwd)/helpers.sh
|
|||||||
|
|
||||||
travis_fold start prepare_selftests "Building selftests"
|
travis_fold start prepare_selftests "Building selftests"
|
||||||
|
|
||||||
LLVM_VER=12
|
sudo apt-get -y install python-docutils # for rst2man
|
||||||
|
|
||||||
|
LLVM_VER=14
|
||||||
LIBBPF_PATH="${REPO_ROOT}"
|
LIBBPF_PATH="${REPO_ROOT}"
|
||||||
REPO_PATH="travis-ci/vmtest/bpf-next"
|
|
||||||
|
|
||||||
PREPARE_SELFTESTS_SCRIPT=${VMTEST_ROOT}/prepare_selftests-${KERNEL}.sh
|
PREPARE_SELFTESTS_SCRIPT=${VMTEST_ROOT}/prepare_selftests-${KERNEL}.sh
|
||||||
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
|
if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
|
||||||
@@ -28,7 +29,7 @@ make \
|
|||||||
VMLINUX_BTF="${VMLINUX_BTF}" \
|
VMLINUX_BTF="${VMLINUX_BTF}" \
|
||||||
VMLINUX_H=${VMLINUX_H} \
|
VMLINUX_H=${VMLINUX_H} \
|
||||||
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||||
-j $((2*$(nproc)))
|
-j $((4*$(nproc))) >/dev/null
|
||||||
mkdir ${LIBBPF_PATH}/selftests
|
mkdir ${LIBBPF_PATH}/selftests
|
||||||
cp -R "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
cp -R "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||||
${LIBBPF_PATH}/selftests
|
${LIBBPF_PATH}/selftests
|
||||||
|
|||||||
@@ -8,12 +8,22 @@ CWD=$(pwd)
|
|||||||
LIBBPF_PATH=$(pwd)
|
LIBBPF_PATH=$(pwd)
|
||||||
REPO_PATH=$1
|
REPO_PATH=$1
|
||||||
|
|
||||||
BPF_NEXT_ORIGIN=https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
|
KERNEL_ORIGIN=${KERNEL_ORIGIN:-https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git}
|
||||||
LINUX_SHA=$(cat ${LIBBPF_PATH}/CHECKPOINT-COMMIT)
|
KERNEL_BRANCH=${KERNEL_BRANCH:-CHECKPOINT}
|
||||||
SNAPSHOT_URL=https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/snapshot/bpf-next-${LINUX_SHA}.tar.gz
|
if [[ "${KERNEL_BRANCH}" = 'CHECKPOINT' ]]; then
|
||||||
|
echo "using CHECKPOINT sha1"
|
||||||
|
LINUX_SHA=$(cat ${LIBBPF_PATH}/CHECKPOINT-COMMIT)
|
||||||
|
else
|
||||||
|
echo "using ${KERNEL_BRANCH} sha1"
|
||||||
|
LINUX_SHA=$(git ls-remote ${KERNEL_ORIGIN} ${KERNEL_BRANCH} | awk '{print $1}')
|
||||||
|
fi
|
||||||
|
SNAPSHOT_URL=${KERNEL_ORIGIN}/snapshot/bpf-next-${LINUX_SHA}.tar.gz
|
||||||
|
|
||||||
echo REPO_PATH = ${REPO_PATH}
|
echo REPO_PATH = ${REPO_PATH}
|
||||||
|
|
||||||
|
echo KERNEL_ORIGIN = ${KERNEL_ORIGIN}
|
||||||
echo LINUX_SHA = ${LINUX_SHA}
|
echo LINUX_SHA = ${LINUX_SHA}
|
||||||
|
echo SNAPSHOT_URL = ${SNAPSHOT_URL}
|
||||||
|
|
||||||
if [ ! -d "${REPO_PATH}" ]; then
|
if [ ! -d "${REPO_PATH}" ]; then
|
||||||
echo
|
echo
|
||||||
@@ -22,14 +32,14 @@ if [ ! -d "${REPO_PATH}" ]; then
|
|||||||
mkdir -p $(dirname "${REPO_PATH}")
|
mkdir -p $(dirname "${REPO_PATH}")
|
||||||
cd $(dirname "${REPO_PATH}")
|
cd $(dirname "${REPO_PATH}")
|
||||||
# attempt to fetch desired bpf-next repo snapshot
|
# attempt to fetch desired bpf-next repo snapshot
|
||||||
if wget ${SNAPSHOT_URL} && tar xf bpf-next-${LINUX_SHA}.tar.gz ; then
|
if wget -nv ${SNAPSHOT_URL} && tar xf bpf-next-${LINUX_SHA}.tar.gz --totals ; then
|
||||||
mv bpf-next-${LINUX_SHA} $(basename ${REPO_PATH})
|
mv bpf-next-${LINUX_SHA} $(basename ${REPO_PATH})
|
||||||
else
|
else
|
||||||
# but fallback to git fetch approach if that fails
|
# but fallback to git fetch approach if that fails
|
||||||
mkdir -p $(basename ${REPO_PATH})
|
mkdir -p $(basename ${REPO_PATH})
|
||||||
cd $(basename ${REPO_PATH})
|
cd $(basename ${REPO_PATH})
|
||||||
git init
|
git init
|
||||||
git remote add bpf-next ${BPF_NEXT_ORIGIN}
|
git remote add bpf-next ${KERNEL_ORIGIN}
|
||||||
# try shallow clone first
|
# try shallow clone first
|
||||||
git fetch --depth 32 bpf-next
|
git fetch --depth 32 bpf-next
|
||||||
# check if desired SHA exists
|
# check if desired SHA exists
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# PERMANENTLY DISABLED
|
# PERMANENTLY DISABLED
|
||||||
align # verifier output format changed
|
align # verifier output format changed
|
||||||
|
atomics # new atomic operations (v5.12+)
|
||||||
|
atomic_bounds # new atomic operations (v5.12+)
|
||||||
|
bind_perm # changed semantics of return values (v5.12+)
|
||||||
|
bpf_cookie # 5.15+
|
||||||
bpf_iter # bpf_iter support is missing
|
bpf_iter # bpf_iter support is missing
|
||||||
bpf_obj_id # bpf_link support missing for GET_OBJ_INFO, GET_FD_BY_ID, etc
|
bpf_obj_id # bpf_link support missing for GET_OBJ_INFO, GET_FD_BY_ID, etc
|
||||||
bpf_tcp_ca # STRUCT_OPS is missing
|
bpf_tcp_ca # STRUCT_OPS is missing
|
||||||
@@ -9,6 +13,7 @@ cg_storage_multi # v5.9+ functionality
|
|||||||
cgroup_attach_multi # BPF_F_REPLACE_PROG missing
|
cgroup_attach_multi # BPF_F_REPLACE_PROG missing
|
||||||
cgroup_link # LINK_CREATE is missing
|
cgroup_link # LINK_CREATE is missing
|
||||||
cgroup_skb_sk_lookup # bpf_sk_lookup_tcp() helper is missing
|
cgroup_skb_sk_lookup # bpf_sk_lookup_tcp() helper is missing
|
||||||
|
check_mtu # missing BPF helper (v5.12+)
|
||||||
cls_redirect # bpf_csum_level() helper is missing
|
cls_redirect # bpf_csum_level() helper is missing
|
||||||
connect_force_port # cgroup/get{peer,sock}name{4,6} support is missing
|
connect_force_port # cgroup/get{peer,sock}name{4,6} support is missing
|
||||||
d_path # v5.10+ feature
|
d_path # v5.10+ feature
|
||||||
@@ -16,29 +21,39 @@ enable_stats # BPF_ENABLE_STATS support is missing
|
|||||||
fentry_fexit # bpf_prog_test_tracing missing
|
fentry_fexit # bpf_prog_test_tracing missing
|
||||||
fentry_test # bpf_prog_test_tracing missing
|
fentry_test # bpf_prog_test_tracing missing
|
||||||
fexit_bpf2bpf # freplace is missing
|
fexit_bpf2bpf # freplace is missing
|
||||||
|
fexit_sleep # relies on bpf_trampoline fix in 5.12+
|
||||||
fexit_test # bpf_prog_test_tracing missing
|
fexit_test # bpf_prog_test_tracing missing
|
||||||
flow_dissector # bpf_link-based flow dissector is in 5.8+
|
flow_dissector # bpf_link-based flow dissector is in 5.8+
|
||||||
flow_dissector_reattach
|
flow_dissector_reattach
|
||||||
|
for_each # v5.12+
|
||||||
|
get_func_ip_test # v5.15+
|
||||||
get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
|
get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
|
||||||
hash_large_key # v5.11+
|
hash_large_key # v5.11+
|
||||||
ima # v5.11+
|
ima # v5.11+
|
||||||
kfree_skb # 32-bit pointer arith in test_pkt_access
|
kfree_skb # 32-bit pointer arith in test_pkt_access
|
||||||
ksyms # __start_BTF has different name
|
ksyms # __start_BTF has different name
|
||||||
|
kfunc_call # v5.13+
|
||||||
link_pinning # bpf_link is missing
|
link_pinning # bpf_link is missing
|
||||||
|
linked_vars # v5.13+
|
||||||
load_bytes_relative # new functionality in 5.8
|
load_bytes_relative # new functionality in 5.8
|
||||||
|
lookup_and_delete # v5.14+
|
||||||
map_init # per-CPU LRU missing
|
map_init # per-CPU LRU missing
|
||||||
map_ptr # test uses BPF_MAP_TYPE_RINGBUF, added in 5.8
|
map_ptr # test uses BPF_MAP_TYPE_RINGBUF, added in 5.8
|
||||||
metadata # v5.10+
|
metadata # v5.10+
|
||||||
|
migrate_reuseport # v5.14+
|
||||||
mmap # 5.5 kernel is too permissive with re-mmaping
|
mmap # 5.5 kernel is too permissive with re-mmaping
|
||||||
modify_return # fmod_ret support is missing
|
modify_return # fmod_ret support is missing
|
||||||
module_attach # module BTF support missing (v5.11+)
|
module_attach # module BTF support missing (v5.11+)
|
||||||
|
netcnt
|
||||||
ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
|
ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
|
||||||
pe_preserve_elems # v5.10+
|
pe_preserve_elems # v5.10+
|
||||||
perf_branches # bpf_read_branch_records() helper is missing
|
perf_branches # bpf_read_branch_records() helper is missing
|
||||||
|
perf_link # v5.15+
|
||||||
pkt_access # 32-bit pointer arith in test_pkt_access
|
pkt_access # 32-bit pointer arith in test_pkt_access
|
||||||
probe_read_user_str # kernel bug with garbage bytes at the end
|
probe_read_user_str # kernel bug with garbage bytes at the end
|
||||||
prog_run_xattr # 32-bit pointer arith in test_pkt_access
|
prog_run_xattr # 32-bit pointer arith in test_pkt_access
|
||||||
raw_tp_test_run # v5.10+
|
raw_tp_test_run # v5.10+
|
||||||
|
recursion # v5.12+
|
||||||
ringbuf # BPF_MAP_TYPE_RINGBUF is supported in 5.8+
|
ringbuf # BPF_MAP_TYPE_RINGBUF is supported in 5.8+
|
||||||
|
|
||||||
# bug in verifier w/ tracking references
|
# bug in verifier w/ tracking references
|
||||||
@@ -48,17 +63,24 @@ reference_tracking
|
|||||||
select_reuseport # UDP support is missing
|
select_reuseport # UDP support is missing
|
||||||
send_signal # bpf_send_signal_thread() helper is missing
|
send_signal # bpf_send_signal_thread() helper is missing
|
||||||
sk_assign # bpf_sk_assign helper missing
|
sk_assign # bpf_sk_assign helper missing
|
||||||
skb_helpers # helpers added in 5.8+
|
sk_lookup # v5.9+
|
||||||
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
sk_storage_tracing # missing bpf_sk_storage_get() helper
|
||||||
|
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
||||||
|
skb_helpers # helpers added in 5.8+
|
||||||
|
snprintf # v5.13+
|
||||||
snprintf_btf # v5.10+
|
snprintf_btf # v5.10+
|
||||||
sock_fields # v5.10+
|
sock_fields # v5.10+
|
||||||
|
socket_cookie # v5.12+
|
||||||
sockmap_basic # uses new socket fields, 5.8+
|
sockmap_basic # uses new socket fields, 5.8+
|
||||||
sockmap_listen # no listen socket supportin SOCKMAP
|
sockmap_listen # no listen socket supportin SOCKMAP
|
||||||
sockopt_sk
|
sockopt_sk
|
||||||
sk_lookup # v5.9+
|
stacktrace_build_id # v5.9+
|
||||||
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
stack_var_off # v5.12+
|
||||||
|
syscall # v5.14+
|
||||||
|
task_local_storage # v5.12+
|
||||||
tcp_hdr_options # v5.10+, new TCP header options feature in BPF
|
tcp_hdr_options # v5.10+, new TCP header options feature in BPF
|
||||||
tcpbpf_user # LINK_CREATE is missing
|
tcpbpf_user # LINK_CREATE is missing
|
||||||
|
tc_redirect # v5.14+
|
||||||
test_bpffs # v5.10+, new CONFIG_BPF_PRELOAD=y and CONFIG_BPF_PRELOAD_UMG=y|m
|
test_bpffs # v5.10+, new CONFIG_BPF_PRELOAD=y and CONFIG_BPF_PRELOAD_UMG=y|m
|
||||||
test_bprm_opts # v5.11+
|
test_bprm_opts # v5.11+
|
||||||
test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
|
test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
|
||||||
@@ -67,13 +89,19 @@ test_lsm # no BPF_LSM support
|
|||||||
test_overhead # no fmod_ret support
|
test_overhead # no fmod_ret support
|
||||||
test_profiler # needs verifier logic improvements from v5.10+
|
test_profiler # needs verifier logic improvements from v5.10+
|
||||||
test_skb_pkt_end # v5.11+
|
test_skb_pkt_end # v5.11+
|
||||||
|
timer # v5.15+
|
||||||
|
timer_mim # v5.15+
|
||||||
trace_ext # v5.10+
|
trace_ext # v5.10+
|
||||||
|
trace_printk # v5.14+
|
||||||
|
trampoline_count # v5.12+ have lower allowed limits
|
||||||
udp_limit # no cgroup/sock_release BPF program type (5.9+)
|
udp_limit # no cgroup/sock_release BPF program type (5.9+)
|
||||||
varlen # verifier bug fixed in later kernels
|
varlen # verifier bug fixed in later kernels
|
||||||
vmlinux # hrtimer_nanosleep() signature changed incompatibly
|
vmlinux # hrtimer_nanosleep() signature changed incompatibly
|
||||||
xdp_adjust_tail # new XDP functionality added in 5.8
|
xdp_adjust_tail # new XDP functionality added in 5.8
|
||||||
xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
|
xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
|
||||||
|
xdp_bonding # v5.15+
|
||||||
xdp_bpf2bpf # freplace is missing
|
xdp_bpf2bpf # freplace is missing
|
||||||
|
xdp_context_test_run # v5.15+
|
||||||
xdp_cpumap_attach # v5.9+
|
xdp_cpumap_attach # v5.9+
|
||||||
xdp_devmap_attach # new feature in 5.8
|
xdp_devmap_attach # new feature in 5.8
|
||||||
xdp_link # v5.9+
|
xdp_link # v5.9+
|
||||||
|
|||||||
@@ -1486,7 +1486,7 @@ CONFIG_SCSI_MOD=y
|
|||||||
# CONFIG_MACINTOSH_DRIVERS is not set
|
# CONFIG_MACINTOSH_DRIVERS is not set
|
||||||
CONFIG_NETDEVICES=y
|
CONFIG_NETDEVICES=y
|
||||||
CONFIG_NET_CORE=y
|
CONFIG_NET_CORE=y
|
||||||
# CONFIG_BONDING is not set
|
CONFIG_BONDING=y
|
||||||
# CONFIG_DUMMY is not set
|
# CONFIG_DUMMY is not set
|
||||||
# CONFIG_WIREGUARD is not set
|
# CONFIG_WIREGUARD is not set
|
||||||
# CONFIG_EQUALIZER is not set
|
# CONFIG_EQUALIZER is not set
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
btf_dump
|
# btf_dump -- need to disable data dump sub-tests
|
||||||
core_retro
|
core_retro
|
||||||
cpu_mask
|
cpu_mask
|
||||||
hashmap
|
hashmap
|
||||||
|
|||||||
@@ -2,11 +2,23 @@
|
|||||||
# $2 - fold identifier, no spaces
|
# $2 - fold identifier, no spaces
|
||||||
# $3 - fold section description
|
# $3 - fold section description
|
||||||
travis_fold() {
|
travis_fold() {
|
||||||
local YELLOW='\033[1;33m'
|
local YELLOW='\033[1;33m'
|
||||||
local NOCOLOR='\033[0m'
|
local NOCOLOR='\033[0m'
|
||||||
echo travis_fold:$1:$2
|
if [ -z ${GITHUB_WORKFLOW+x} ]; then
|
||||||
if [ ! -z "${3:-}" ]; then
|
echo travis_fold:$1:$2
|
||||||
echo -e "${YELLOW}$3${NOCOLOR}"
|
if [ ! -z "${3:-}" ]; then
|
||||||
fi
|
echo -e "${YELLOW}$3${NOCOLOR}"
|
||||||
echo
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,18 @@ set -eu
|
|||||||
|
|
||||||
source $(cd $(dirname $0) && pwd)/helpers.sh
|
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||||
|
|
||||||
REPO_PATH=$1
|
REPO_PATH=${1:-}
|
||||||
|
|
||||||
${VMTEST_ROOT}/checkout_latest_kernel.sh ${REPO_PATH}
|
if [[ ! -z "$REPO_PATH" ]]; then
|
||||||
cd ${REPO_PATH}
|
${VMTEST_ROOT}/checkout_latest_kernel.sh ${REPO_PATH}
|
||||||
|
cd ${REPO_PATH}
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||||
travis_fold start build_kernel "Kernel build"
|
travis_fold start build_kernel "Kernel build"
|
||||||
|
|
||||||
cp ${VMTEST_ROOT}/configs/latest.config .config
|
cp ${VMTEST_ROOT}/configs/latest.config .config
|
||||||
make -j $((4*$(nproc))) olddefconfig all
|
make -j $((4*$(nproc))) olddefconfig all >/dev/null
|
||||||
|
|
||||||
travis_fold end build_kernel
|
travis_fold end build_kernel
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ SKIPSOURCE=0
|
|||||||
APPEND=""
|
APPEND=""
|
||||||
DIR="$PWD"
|
DIR="$PWD"
|
||||||
LIST=0
|
LIST=0
|
||||||
|
|
||||||
|
# by default will copy all files that aren't listed in git exclusions
|
||||||
|
# but it doesn't work for entire kernel tree very well
|
||||||
|
# so for full kernel tree you may need to SOURCE_FULLCOPY=0
|
||||||
|
SOURCE_FULLCOPY=${SOURCE_FULLCOPY:-1}
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-k|--kernel)
|
-k|--kernel)
|
||||||
@@ -374,27 +380,38 @@ fi
|
|||||||
|
|
||||||
travis_fold end vmlinux_setup
|
travis_fold end vmlinux_setup
|
||||||
|
|
||||||
|
REPO_PATH="${SELFTEST_REPO_PATH:-travis-ci/vmtest/bpf-next}"
|
||||||
LIBBPF_PATH="${REPO_ROOT}" \
|
LIBBPF_PATH="${REPO_ROOT}" \
|
||||||
REPO_PATH="travis-ci/vmtest/bpf-next" \
|
|
||||||
VMTEST_ROOT="${VMTEST_ROOT}" \
|
VMTEST_ROOT="${VMTEST_ROOT}" \
|
||||||
|
REPO_PATH="${REPO_PATH}" \
|
||||||
VMLINUX_BTF=${vmlinux} ${VMTEST_ROOT}/build_selftests.sh
|
VMLINUX_BTF=${vmlinux} ${VMTEST_ROOT}/build_selftests.sh
|
||||||
|
|
||||||
|
travis_fold start bpftool_checks "Running bpftool checks..."
|
||||||
|
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||||
|
"${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf/test_bpftool_synctypes.py" && \
|
||||||
|
echo "Consistency checks passed successfully."
|
||||||
|
else
|
||||||
|
echo "Consistency checks skipped."
|
||||||
|
fi
|
||||||
|
travis_fold end bpftool_checks
|
||||||
|
|
||||||
travis_fold start vm_init "Starting virtual machine..."
|
travis_fold start vm_init "Starting virtual machine..."
|
||||||
|
|
||||||
if (( SKIPSOURCE )); then
|
if (( SKIPSOURCE )); then
|
||||||
echo "Not copying source files..." >&2
|
echo "Not copying source files..." >&2
|
||||||
else
|
else
|
||||||
echo "Copying source files..." >&2
|
echo "Copying source files..." >&2
|
||||||
|
|
||||||
# Copy the source files in.
|
# Copy the source files in.
|
||||||
sudo mkdir -p -m 0755 "$mnt/${PROJECT_NAME}"
|
sudo mkdir -p -m 0755 "$mnt/${PROJECT_NAME}"
|
||||||
{
|
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
||||||
if [[ -e .git ]]; then
|
git ls-files -z | sudo rsync --files-from=- -0cpt . "$mnt/${PROJECT_NAME}"
|
||||||
git ls-files -z
|
|
||||||
else
|
else
|
||||||
tr '\n' '\0' < "${PROJECT_NAME}.egg-info/SOURCES.txt"
|
sudo mkdir -p -m 0755 ${mnt}/${PROJECT_NAME}/{selftests,travis-ci}
|
||||||
fi
|
tree --du -shaC "${REPO_ROOT}/selftests/bpf"
|
||||||
} | sudo rsync --files-from=- -0cpt . "$mnt/${PROJECT_NAME}"
|
sudo rsync -avm "${REPO_ROOT}/selftests/bpf" "$mnt/${PROJECT_NAME}/selftests/"
|
||||||
|
sudo rsync -avm "${REPO_ROOT}/travis-ci/vmtest" "$mnt/${PROJECT_NAME}/travis-ci/"
|
||||||
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setup_script="#!/bin/sh
|
setup_script="#!/bin/sh
|
||||||
@@ -415,17 +432,18 @@ set -eux
|
|||||||
|
|
||||||
echo 'Running setup commands'
|
echo 'Running setup commands'
|
||||||
%s
|
%s
|
||||||
%s
|
set +e; %s; exitstatus=\$?; set -e
|
||||||
echo $? > /exitstatus
|
echo \$exitstatus > /exitstatus
|
||||||
chmod 644 /exitstatus" "${setup_envvars}" "${setup_cmd}")
|
chmod 644 /exitstatus" "${setup_envvars}" "${setup_cmd}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "${setup_script}" | sudo tee "$mnt/etc/rcS.d/S50-run-tests" > /dev/null
|
echo "${setup_script}" | sudo tee "$mnt/etc/rcS.d/S50-run-tests" > /dev/null
|
||||||
sudo chmod 755 "$mnt/etc/rcS.d/S50-run-tests"
|
sudo chmod 755 "$mnt/etc/rcS.d/S50-run-tests"
|
||||||
|
|
||||||
|
fold_shutdown="$(travis_fold start shutdown)"
|
||||||
poweroff_script="#!/bin/sh
|
poweroff_script="#!/bin/sh
|
||||||
|
|
||||||
echo travis_fold:start:shutdown
|
echo ${fold_shutdown}
|
||||||
echo -e '\033[1;33mShutdown\033[0m\n'
|
echo -e '\033[1;33mShutdown\033[0m\n'
|
||||||
|
|
||||||
poweroff"
|
poweroff"
|
||||||
@@ -436,11 +454,15 @@ sudo umount "$mnt"
|
|||||||
|
|
||||||
echo "Starting VM with $(nproc) CPUs..."
|
echo "Starting VM with $(nproc) CPUs..."
|
||||||
|
|
||||||
|
if kvm-ok ; then
|
||||||
|
accel="-cpu kvm64 -enable-kvm"
|
||||||
|
else
|
||||||
|
accel="-cpu qemu64 -machine accel=tcg"
|
||||||
|
fi
|
||||||
qemu-system-x86_64 -nodefaults -display none -serial mon:stdio \
|
qemu-system-x86_64 -nodefaults -display none -serial mon:stdio \
|
||||||
-cpu kvm64 -enable-kvm -smp "$(nproc)" -m 4G \
|
${accel} -smp "$(nproc)" -m 4G \
|
||||||
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
||||||
-kernel "$vmlinuz" -append "root=/dev/vda rw console=ttyS0,115200$APPEND"
|
-kernel "$vmlinuz" -append "root=/dev/vda rw console=ttyS0,115200$APPEND"
|
||||||
|
|
||||||
sudo mount -o loop "$IMG" "$mnt"
|
sudo mount -o loop "$IMG" "$mnt"
|
||||||
if exitstatus="$(cat "$mnt/exitstatus" 2>/dev/null)"; then
|
if exitstatus="$(cat "$mnt/exitstatus" 2>/dev/null)"; then
|
||||||
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
||||||
|
|||||||
@@ -46,6 +46,6 @@ cd libbpf/selftests/bpf
|
|||||||
test_progs
|
test_progs
|
||||||
|
|
||||||
if [[ "${KERNEL}" == 'latest' ]]; then
|
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||||
#test_maps
|
# test_maps
|
||||||
test_verifier
|
test_verifier
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ set -eu
|
|||||||
|
|
||||||
source $(cd $(dirname $0) && pwd)/helpers.sh
|
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||||
|
|
||||||
VMTEST_SETUPCMD="PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
|
VMTEST_SETUPCMD="GITHUB_WORKFLOW=${GITHUB_WORKFLOW:-} PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
|
||||||
|
|
||||||
|
# if CHECKOUT_KERNEL is 1 code will consider that kernel code lives elsewhere
|
||||||
|
# if 0 it will consider that REPO_ROOT is a kernel tree
|
||||||
|
CHECKOUT_KERNEL=${CHECKOUT_KERNEL:-1}
|
||||||
|
|
||||||
echo "KERNEL: $KERNEL"
|
echo "KERNEL: $KERNEL"
|
||||||
echo
|
echo
|
||||||
@@ -14,17 +18,22 @@ ${VMTEST_ROOT}/build_pahole.sh travis-ci/vmtest/pahole
|
|||||||
|
|
||||||
travis_fold start install_clang "Installing Clang/LLVM"
|
travis_fold start install_clang "Installing Clang/LLVM"
|
||||||
|
|
||||||
# Install required packages
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main" | sudo tee -a /etc/apt/sources.list
|
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install clang-12 lld-12 llvm-12
|
sudo apt-get install --allow-downgrades -y libc6=2.31-0ubuntu9.2
|
||||||
sudo apt-get -y install python-docutils # for rst2man
|
sudo aptitude install -y g++ libelf-dev
|
||||||
|
sudo aptitude install -y clang-14 lld-14 llvm-14
|
||||||
|
|
||||||
travis_fold end install_clang
|
travis_fold end install_clang
|
||||||
|
|
||||||
# Build selftests (and latest kernel, if necessary)
|
# Build selftests (and latest kernel, if necessary)
|
||||||
KERNEL="${KERNEL}" ${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
|
|
||||||
|
if [[ "$CHECKOUT_KERNEL" == "1" ]]; then
|
||||||
|
${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
|
||||||
|
else
|
||||||
|
${VMTEST_ROOT}/prepare_selftests.sh
|
||||||
|
fi
|
||||||
|
|
||||||
# Escape whitespace characters.
|
# Escape whitespace characters.
|
||||||
setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
||||||
@@ -32,7 +41,11 @@ setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
|||||||
sudo adduser "${USER}" kvm
|
sudo adduser "${USER}" kvm
|
||||||
|
|
||||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img;
|
if [[ "$CHECKOUT_KERNEL" == "1" ]]; then
|
||||||
|
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img
|
||||||
|
else
|
||||||
|
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b "${REPO_ROOT}" -o -d ~ -s "${setup_cmd}" ~/root.img
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img;
|
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img
|
||||||
fi
|
fi
|
||||||
|
|||||||
103476
travis-ci/vmtest/vmlinux.h
103476
travis-ci/vmtest/vmlinux.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user