mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-13 21:09:07 +08:00
Compare commits
118 Commits
netdata_pa
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4884bf3dbd | ||
|
|
690d0531f9 | ||
|
|
7cda69caeb | ||
|
|
1f7db672e4 | ||
|
|
385b2d1738 | ||
|
|
7f11cd48d6 | ||
|
|
4374bad784 | ||
|
|
55b057565f | ||
|
|
472c0726e8 | ||
|
|
c86cb27d5b | ||
|
|
3ef05a585e | ||
|
|
493bfa8a59 | ||
|
|
9f006f1ed6 | ||
|
|
5fc0d66cad | ||
|
|
37c3e92657 | ||
|
|
25eb5c4e02 | ||
|
|
07e4e0cb04 | ||
|
|
316b60fa89 | ||
|
|
6cfb97c561 | ||
|
|
5c31bcf220 | ||
|
|
5b4dbd8141 | ||
|
|
14e12f4290 | ||
|
|
60ce9af668 | ||
|
|
d29571725a | ||
|
|
842c5b7bff | ||
|
|
9109d6a4b4 | ||
|
|
eab19ffead | ||
|
|
94a49850c5 | ||
|
|
d71409b508 | ||
|
|
f0ecdeed3a | ||
|
|
d924fa62ee | ||
|
|
0f5a62b2d8 | ||
|
|
5ca49d2b32 | ||
|
|
219c8e11e0 | ||
|
|
140b902274 | ||
|
|
1987a34fc9 | ||
|
|
3b1714aa92 | ||
|
|
554054d876 | ||
|
|
26e196d449 | ||
|
|
3fac0b3d08 | ||
|
|
ac4a0fa400 | ||
|
|
6ad73f5083 | ||
|
|
8a52e49575 | ||
|
|
5b9d079c7f | ||
|
|
bc66d28b68 | ||
|
|
98181e0546 | ||
|
|
d932a1a46b | ||
|
|
011a01594c | ||
|
|
b9a88a4533 | ||
|
|
969018545d | ||
|
|
0e80b7dc3f | ||
|
|
932800b20b | ||
|
|
cfc69268e5 | ||
|
|
9b2bbdefd5 | ||
|
|
c7236a5342 | ||
|
|
a611094604 | ||
|
|
9b422137af | ||
|
|
65cdd0c73d | ||
|
|
6b2db898cc | ||
|
|
ea6c242fc6 | ||
|
|
26e768783c | ||
|
|
88209a3c44 | ||
|
|
2ab2615926 | ||
|
|
c03b183a6e | ||
|
|
36cc591ac8 | ||
|
|
3acf7c289a | ||
|
|
a383b3e200 | ||
|
|
2f52e2afc0 | ||
|
|
738277b773 | ||
|
|
16dfb4ffe4 | ||
|
|
826770613d | ||
|
|
277846bc6c | ||
|
|
1e97e84c86 | ||
|
|
17d7f04e7c | ||
|
|
c4f9ee9fbb | ||
|
|
6fd2ee5486 | ||
|
|
7beaa2ef90 | ||
|
|
a0195b3078 | ||
|
|
bedab00b50 | ||
|
|
c95bf6714d | ||
|
|
8e697cf9fd | ||
|
|
1dd20d7144 | ||
|
|
28c8a2c179 | ||
|
|
11f873fd5b | ||
|
|
50041f432d | ||
|
|
87a9622982 | ||
|
|
5b732fc1d8 | ||
|
|
ffc5139acd | ||
|
|
cfbdceb99d | ||
|
|
9871f15dd6 | ||
|
|
93c109c9ee | ||
|
|
eaea2bce02 | ||
|
|
f05791d8cf | ||
|
|
2bb8f041b0 | ||
|
|
50ae3acfe9 | ||
|
|
07ba0eeb8e | ||
|
|
b15d479ef7 | ||
|
|
d374094d8c | ||
|
|
19d260d144 | ||
|
|
f1558d7a23 | ||
|
|
596c9a2d77 | ||
|
|
eb10610a3b | ||
|
|
d7982f3948 | ||
|
|
76b4bf4295 | ||
|
|
5bf62459b1 | ||
|
|
421213a052 | ||
|
|
4cafbf7527 | ||
|
|
f687443178 | ||
|
|
38fb8cfc0c | ||
|
|
45115706b6 | ||
|
|
bde69b0ee0 | ||
|
|
19c6144c09 | ||
|
|
760c39208c | ||
|
|
fa93001e85 | ||
|
|
50028712c4 | ||
|
|
0f3ba10651 | ||
|
|
ebf17ac628 | ||
|
|
06390e2371 |
2
.github/actions/setup/action.yml
vendored
2
.github/actions/setup/action.yml
vendored
@@ -12,7 +12,7 @@ runs:
|
||||
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 sudo apt-get install -y aptitude qemu-kvm zstd binutils-dev elfutils libcap-dev libelf-dev libdw-dev libguestfs-tools >> /tmp/ci_setup
|
||||
echo export PROJECT_NAME='libbpf' >> /tmp/ci_setup
|
||||
echo export AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")" >> /tmp/ci_setup
|
||||
echo export REPO_ROOT=$GITHUB_WORKSPACE >> /tmp/ci_setup
|
||||
|
||||
40
.github/workflows/cifuzz.yml
vendored
Normal file
40
.github/workflows/cifuzz.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
# https://google.github.io/oss-fuzz/getting-started/continuous-integration/
|
||||
name: CIFuzz
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sanitizer: [address, undefined, memory]
|
||||
steps:
|
||||
- name: Build Fuzzers (${{ matrix.sanitizer }})
|
||||
id: build
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libbpf'
|
||||
dry-run: false
|
||||
allowed-broken-targets-percentage: 0
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Run Fuzzers (${{ matrix.sanitizer }})
|
||||
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||
with:
|
||||
oss-fuzz-project-name: 'libbpf'
|
||||
fuzz-seconds: 300
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
path: ./out/artifacts
|
||||
1
.github/workflows/coverity.yml
vendored
1
.github/workflows/coverity.yml
vendored
@@ -8,6 +8,7 @@ on:
|
||||
jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'libbpf/libbpf'
|
||||
name: Coverity
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
9
.github/workflows/test.yml
vendored
9
.github/workflows/test.yml
vendored
@@ -12,15 +12,20 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
vmtest:
|
||||
runs-on: ubuntu-latest
|
||||
name: Kernel ${{ matrix.kernel }} + selftests
|
||||
runs-on: ${{ matrix.runs_on }}
|
||||
name: Kernel ${{ matrix.kernel }} on ${{ matrix.runs_on }} + selftests
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- kernel: 'LATEST'
|
||||
runs_on: ubuntu-latest
|
||||
- kernel: 'LATEST'
|
||||
runs_on: z15
|
||||
- kernel: '5.5.0'
|
||||
runs_on: ubuntu-latest
|
||||
- kernel: '4.9.0'
|
||||
runs_on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout
|
||||
|
||||
@@ -1 +1 @@
|
||||
8d6c414cd2fb74aa6812e9bfec6178f8246c4f3a
|
||||
c0d95d3380ee099d735e08618c0d599e72f6c8b0
|
||||
|
||||
@@ -1 +1 @@
|
||||
5319255b8df9271474bc9027cabf82253934f28d
|
||||
43174f0d4597325cb91f1f1f55263eb6e6101036
|
||||
|
||||
@@ -19,6 +19,11 @@ the examples of building BPF applications with libbpf.
|
||||
[libbpf-tools](https://github.com/iovisor/bcc/tree/master/libbpf-tools) are also
|
||||
a good source of the real-world libbpf-based tracing tools.
|
||||
|
||||
See also ["BPF CO-RE reference guide"](https://nakryiko.com/posts/bpf-core-reference-guide/)
|
||||
for the coverage of practical aspects of building BPF CO-RE applications and
|
||||
["BPF CO-RE"](https://nakryiko.com/posts/bpf-portability-and-co-re/) for
|
||||
general introduction into BPF portability issues and BPF CO-RE origins.
|
||||
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
||||
their application, should be sent to bpf@vger.kernel.org mailing list. You can
|
||||
subscribe to it [here](http://vger.kernel.org/vger-lists.html#bpf) and search
|
||||
@@ -35,6 +40,7 @@ Build
|
||||
[](https://github.com/libbpf/libbpf/actions/workflows/test.yml)
|
||||
[](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
|
||||
[](https://scan.coverity.com/projects/libbpf)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libbpf)
|
||||
=====
|
||||
libelf is an internal dependency of libbpf and thus it is required to link
|
||||
against and must be installed on the system for applications to work.
|
||||
@@ -140,6 +146,7 @@ Otherwise, please make sure to update it on your system.
|
||||
|
||||
The following resources are useful to understand what BPF CO-RE is and how to
|
||||
use it:
|
||||
- [BPF CO-RE reference guide](https://nakryiko.com/posts/bpf-core-reference-guide/)
|
||||
- [BPF Portability and CO-RE](https://nakryiko.com/posts/bpf-portability-and-co-re/)
|
||||
- [HOWTO: BCC to libbpf conversion](https://nakryiko.com/posts/bcc-to-libbpf-howto-guide/)
|
||||
- [libbpf-tools in BCC repo](https://github.com/iovisor/bcc/tree/master/libbpf-tools)
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
libbpf
|
||||
======
|
||||
|
||||
For API documentation see the `versioned API documentation site <https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
@@ -14,6 +12,8 @@ For API documentation see the `versioned API documentation site <https://libbpf.
|
||||
This is documentation for libbpf, a userspace library for loading and
|
||||
interacting with bpf programs.
|
||||
|
||||
For API documentation see the `versioned API documentation site <https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||
|
||||
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
|
||||
|
||||
@@ -13,6 +13,14 @@
|
||||
.off = OFF, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_ALU32_IMM(OP, DST, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU | BPF_OP(OP) | BPF_K, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_ALU64_IMM(OP, DST, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
|
||||
|
||||
@@ -906,6 +906,7 @@ enum bpf_map_type {
|
||||
BPF_MAP_TYPE_RINGBUF,
|
||||
BPF_MAP_TYPE_INODE_STORAGE,
|
||||
BPF_MAP_TYPE_TASK_STORAGE,
|
||||
BPF_MAP_TYPE_BLOOM_FILTER,
|
||||
};
|
||||
|
||||
/* Note that tracing related programs such as
|
||||
@@ -1274,6 +1275,13 @@ union bpf_attr {
|
||||
* struct stored as the
|
||||
* map value
|
||||
*/
|
||||
/* Any per-map-type extra fields
|
||||
*
|
||||
* BPF_MAP_TYPE_BLOOM_FILTER - the lowest 4 bits indicate the
|
||||
* number of hash functions (if 0, the bloom filter will default
|
||||
* to using 5 hash functions).
|
||||
*/
|
||||
__u64 map_extra;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||
@@ -1736,7 +1744,7 @@ union bpf_attr {
|
||||
* if the maximum number of tail calls has been reached for this
|
||||
* chain of programs. This limit is defined in the kernel by the
|
||||
* macro **MAX_TAIL_CALL_CNT** (not accessible to user space),
|
||||
* which is currently set to 32.
|
||||
* which is currently set to 33.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
@@ -4909,6 +4917,46 @@ union bpf_attr {
|
||||
* Return
|
||||
* The number of bytes written to the buffer, or a negative error
|
||||
* in case of failure.
|
||||
*
|
||||
* struct unix_sock *bpf_skc_to_unix_sock(void *sk)
|
||||
* Description
|
||||
* Dynamically cast a *sk* pointer to a *unix_sock* pointer.
|
||||
* Return
|
||||
* *sk* if casting is valid, or **NULL** otherwise.
|
||||
*
|
||||
* long bpf_kallsyms_lookup_name(const char *name, int name_sz, int flags, u64 *res)
|
||||
* Description
|
||||
* Get the address of a kernel symbol, returned in *res*. *res* is
|
||||
* set to 0 if the symbol is not found.
|
||||
* Return
|
||||
* On success, zero. On error, a negative value.
|
||||
*
|
||||
* **-EINVAL** if *flags* is not zero.
|
||||
*
|
||||
* **-EINVAL** if string *name* is not the same size as *name_sz*.
|
||||
*
|
||||
* **-ENOENT** if symbol is not found.
|
||||
*
|
||||
* **-EPERM** if caller does not have permission to obtain kernel address.
|
||||
*
|
||||
* long bpf_find_vma(struct task_struct *task, u64 addr, void *callback_fn, void *callback_ctx, u64 flags)
|
||||
* Description
|
||||
* Find vma of *task* that contains *addr*, call *callback_fn*
|
||||
* function with *task*, *vma*, and *callback_ctx*.
|
||||
* 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 expected callback signature is
|
||||
*
|
||||
* long (\*callback_fn)(struct task_struct \*task, struct vm_area_struct \*vma, void \*callback_ctx);
|
||||
*
|
||||
* Return
|
||||
* 0 on success.
|
||||
* **-ENOENT** if *task->mm* is NULL, or no vma contains *addr*.
|
||||
* **-EBUSY** if failed to try lock mmap_lock.
|
||||
* **-EINVAL** for invalid **flags**.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -5089,6 +5137,9 @@ union bpf_attr {
|
||||
FN(task_pt_regs), \
|
||||
FN(get_branch_snapshot), \
|
||||
FN(trace_vprintk), \
|
||||
FN(skc_to_unix_sock), \
|
||||
FN(kallsyms_lookup_name), \
|
||||
FN(find_vma), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
@@ -5613,6 +5664,7 @@ struct bpf_prog_info {
|
||||
__u64 run_time_ns;
|
||||
__u64 run_cnt;
|
||||
__u64 recursion_misses;
|
||||
__u32 verified_insns;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_map_info {
|
||||
@@ -5630,6 +5682,8 @@ struct bpf_map_info {
|
||||
__u32 btf_id;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
__u32 :32; /* alignment pad */
|
||||
__u64 map_extra;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_btf_info {
|
||||
@@ -6262,6 +6316,7 @@ struct bpf_sk_lookup {
|
||||
__u32 local_ip4; /* Network byte order */
|
||||
__u32 local_ip6[4]; /* Network byte order */
|
||||
__u32 local_port; /* Host byte order */
|
||||
__u32 ingress_ifindex; /* The arriving interface. Determined by inet_iif. */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -43,7 +43,7 @@ struct btf_type {
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO, VAR and TAG.
|
||||
* FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG.
|
||||
* "type" is a type_id referring to another type.
|
||||
*/
|
||||
union {
|
||||
@@ -74,7 +74,8 @@ enum {
|
||||
BTF_KIND_VAR = 14, /* Variable */
|
||||
BTF_KIND_DATASEC = 15, /* Section */
|
||||
BTF_KIND_FLOAT = 16, /* Floating point */
|
||||
BTF_KIND_TAG = 17, /* Tag */
|
||||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
|
||||
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
@@ -174,14 +175,14 @@ struct btf_var_secinfo {
|
||||
__u32 size;
|
||||
};
|
||||
|
||||
/* BTF_KIND_TAG is followed by a single "struct btf_tag" to describe
|
||||
/* BTF_KIND_DECL_TAG is followed by a single "struct btf_decl_tag" to describe
|
||||
* additional information related to the tag applied location.
|
||||
* If component_idx == -1, the tag is applied to a struct, union,
|
||||
* variable or function. Otherwise, it is applied to a struct/union
|
||||
* member or a func argument, and component_idx indicates which member
|
||||
* or argument (0 ... vlen-1).
|
||||
*/
|
||||
struct btf_tag {
|
||||
struct btf_decl_tag {
|
||||
__s32 component_idx;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ BPF_BRANCH=${3-""}
|
||||
BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||
BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
|
||||
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ] || [ -z "${BPF_BRANCH}" ]; then
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ]; then
|
||||
echo "Error: libbpf or linux repos are not specified"
|
||||
usage
|
||||
fi
|
||||
@@ -74,7 +74,7 @@ commit_desc()
|
||||
}
|
||||
|
||||
# Create commit single-line signature, which consists of:
|
||||
# - full commit hash
|
||||
# - full commit subject
|
||||
# - author date in ISO8601 format
|
||||
# - full commit body with newlines replaced with vertical bars (|)
|
||||
# - shortstat appended at the end
|
||||
@@ -263,8 +263,11 @@ cd_to ${LIBBPF_REPO}
|
||||
git checkout -b ${LIBBPF_SYNC_TAG}
|
||||
|
||||
for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
||||
if ! git am --3way --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||
if ! git am -3 --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||
if ! git apply -3 "${TMP_DIR}/patches/${patch}"; then
|
||||
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||
fi
|
||||
git am --continue
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ ifeq ($(V),1)
|
||||
msg =
|
||||
else
|
||||
Q = @
|
||||
msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
|
||||
msg = @printf ' %-8s %s%s\n' "$(1)" "$(2)" "$(if $(3), $(3))";
|
||||
endif
|
||||
|
||||
LIBBPF_VERSION := $(shell \
|
||||
@@ -20,7 +20,7 @@ ALL_CFLAGS := $(INCLUDES)
|
||||
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall
|
||||
CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
|
||||
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
ifdef NO_PKG_CONFIG
|
||||
|
||||
346
src/bpf.c
346
src/bpf.c
@@ -28,6 +28,7 @@
|
||||
#include <asm/unistd.h>
|
||||
#include <errno.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <limits.h>
|
||||
#include "bpf.h"
|
||||
#include "libbpf.h"
|
||||
#include "libbpf_internal.h"
|
||||
@@ -49,6 +50,12 @@
|
||||
# define __NR_bpf 351
|
||||
# elif defined(__arc__)
|
||||
# define __NR_bpf 280
|
||||
# elif defined(__mips__) && defined(_ABIO32)
|
||||
# define __NR_bpf 4355
|
||||
# elif defined(__mips__) && defined(_ABIN32)
|
||||
# define __NR_bpf 6319
|
||||
# elif defined(__mips__) && defined(_ABI64)
|
||||
# define __NR_bpf 5315
|
||||
# else
|
||||
# error __NR_bpf not defined. libbpf does not support your arch.
|
||||
# endif
|
||||
@@ -65,133 +72,144 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
|
||||
return syscall(__NR_bpf, cmd, attr, size);
|
||||
}
|
||||
|
||||
static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size)
|
||||
static inline int sys_bpf_fd(enum bpf_cmd cmd, union bpf_attr *attr,
|
||||
unsigned int size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = sys_bpf(cmd, attr, size);
|
||||
return ensure_good_fd(fd);
|
||||
}
|
||||
|
||||
#define PROG_LOAD_ATTEMPTS 5
|
||||
|
||||
static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size, int attempts)
|
||||
{
|
||||
int retries = 5;
|
||||
int fd;
|
||||
|
||||
do {
|
||||
fd = sys_bpf(BPF_PROG_LOAD, attr, size);
|
||||
} while (fd < 0 && errno == EAGAIN && retries-- > 0);
|
||||
fd = sys_bpf_fd(BPF_PROG_LOAD, attr, size);
|
||||
} while (fd < 0 && errno == EAGAIN && --attempts > 0);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
||||
int bpf_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
__u32 key_size,
|
||||
__u32 value_size,
|
||||
__u32 max_entries,
|
||||
const struct bpf_map_create_opts *opts)
|
||||
{
|
||||
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
memset(&attr, '\0', sizeof(attr));
|
||||
memset(&attr, 0, attr_sz);
|
||||
|
||||
attr.map_type = create_attr->map_type;
|
||||
attr.key_size = create_attr->key_size;
|
||||
attr.value_size = create_attr->value_size;
|
||||
attr.max_entries = create_attr->max_entries;
|
||||
attr.map_flags = create_attr->map_flags;
|
||||
if (create_attr->name)
|
||||
memcpy(attr.map_name, create_attr->name,
|
||||
min(strlen(create_attr->name), BPF_OBJ_NAME_LEN - 1));
|
||||
attr.numa_node = create_attr->numa_node;
|
||||
attr.btf_fd = create_attr->btf_fd;
|
||||
attr.btf_key_type_id = create_attr->btf_key_type_id;
|
||||
attr.btf_value_type_id = create_attr->btf_value_type_id;
|
||||
attr.map_ifindex = create_attr->map_ifindex;
|
||||
if (attr.map_type == BPF_MAP_TYPE_STRUCT_OPS)
|
||||
attr.btf_vmlinux_value_type_id =
|
||||
create_attr->btf_vmlinux_value_type_id;
|
||||
else
|
||||
attr.inner_map_fd = create_attr->inner_map_fd;
|
||||
if (!OPTS_VALID(opts, bpf_map_create_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
fd = sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||
attr.map_type = map_type;
|
||||
if (map_name)
|
||||
strncat(attr.map_name, map_name, sizeof(attr.map_name) - 1);
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.max_entries = max_entries;
|
||||
|
||||
attr.btf_fd = OPTS_GET(opts, btf_fd, 0);
|
||||
attr.btf_key_type_id = OPTS_GET(opts, btf_key_type_id, 0);
|
||||
attr.btf_value_type_id = OPTS_GET(opts, btf_value_type_id, 0);
|
||||
attr.btf_vmlinux_value_type_id = OPTS_GET(opts, btf_vmlinux_value_type_id, 0);
|
||||
|
||||
attr.inner_map_fd = OPTS_GET(opts, inner_map_fd, 0);
|
||||
attr.map_flags = OPTS_GET(opts, map_flags, 0);
|
||||
attr.map_extra = OPTS_GET(opts, map_extra, 0);
|
||||
attr.numa_node = OPTS_GET(opts, numa_node, 0);
|
||||
attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0);
|
||||
|
||||
fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_map_create_opts, p);
|
||||
|
||||
p.map_flags = create_attr->map_flags;
|
||||
p.numa_node = create_attr->numa_node;
|
||||
p.btf_fd = create_attr->btf_fd;
|
||||
p.btf_key_type_id = create_attr->btf_key_type_id;
|
||||
p.btf_value_type_id = create_attr->btf_value_type_id;
|
||||
p.map_ifindex = create_attr->map_ifindex;
|
||||
if (create_attr->map_type == BPF_MAP_TYPE_STRUCT_OPS)
|
||||
p.btf_vmlinux_value_type_id = create_attr->btf_vmlinux_value_type_id;
|
||||
else
|
||||
p.inner_map_fd = create_attr->inner_map_fd;
|
||||
|
||||
return bpf_map_create(create_attr->map_type, create_attr->name,
|
||||
create_attr->key_size, create_attr->value_size,
|
||||
create_attr->max_entries, &p);
|
||||
}
|
||||
|
||||
int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size, int max_entries,
|
||||
__u32 map_flags, int node)
|
||||
{
|
||||
struct bpf_create_map_attr map_attr = {};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||
|
||||
map_attr.name = name;
|
||||
map_attr.map_type = map_type;
|
||||
map_attr.map_flags = map_flags;
|
||||
map_attr.key_size = key_size;
|
||||
map_attr.value_size = value_size;
|
||||
map_attr.max_entries = max_entries;
|
||||
opts.map_flags = map_flags;
|
||||
if (node >= 0) {
|
||||
map_attr.numa_node = node;
|
||||
map_attr.map_flags |= BPF_F_NUMA_NODE;
|
||||
opts.numa_node = node;
|
||||
opts.map_flags |= BPF_F_NUMA_NODE;
|
||||
}
|
||||
|
||||
return bpf_create_map_xattr(&map_attr);
|
||||
return bpf_map_create(map_type, name, key_size, value_size, max_entries, &opts);
|
||||
}
|
||||
|
||||
int bpf_create_map(enum bpf_map_type map_type, int key_size,
|
||||
int value_size, int max_entries, __u32 map_flags)
|
||||
{
|
||||
struct bpf_create_map_attr map_attr = {};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
|
||||
|
||||
map_attr.map_type = map_type;
|
||||
map_attr.map_flags = map_flags;
|
||||
map_attr.key_size = key_size;
|
||||
map_attr.value_size = value_size;
|
||||
map_attr.max_entries = max_entries;
|
||||
|
||||
return bpf_create_map_xattr(&map_attr);
|
||||
return bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);
|
||||
}
|
||||
|
||||
int bpf_create_map_name(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size, int max_entries,
|
||||
__u32 map_flags)
|
||||
{
|
||||
struct bpf_create_map_attr map_attr = {};
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
|
||||
|
||||
map_attr.name = name;
|
||||
map_attr.map_type = map_type;
|
||||
map_attr.map_flags = map_flags;
|
||||
map_attr.key_size = key_size;
|
||||
map_attr.value_size = value_size;
|
||||
map_attr.max_entries = max_entries;
|
||||
|
||||
return bpf_create_map_xattr(&map_attr);
|
||||
return bpf_map_create(map_type, name, key_size, value_size, max_entries, &opts);
|
||||
}
|
||||
|
||||
int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int inner_map_fd, int max_entries,
|
||||
__u32 map_flags, int node)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
|
||||
memset(&attr, '\0', sizeof(attr));
|
||||
|
||||
attr.map_type = map_type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = 4;
|
||||
attr.inner_map_fd = inner_map_fd;
|
||||
attr.max_entries = max_entries;
|
||||
attr.map_flags = map_flags;
|
||||
if (name)
|
||||
memcpy(attr.map_name, name,
|
||||
min(strlen(name), BPF_OBJ_NAME_LEN - 1));
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||
|
||||
opts.inner_map_fd = inner_map_fd;
|
||||
opts.map_flags = map_flags;
|
||||
if (node >= 0) {
|
||||
attr.map_flags |= BPF_F_NUMA_NODE;
|
||||
attr.numa_node = node;
|
||||
opts.map_flags |= BPF_F_NUMA_NODE;
|
||||
opts.numa_node = node;
|
||||
}
|
||||
|
||||
fd = sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
return bpf_map_create(map_type, name, key_size, 4, max_entries, &opts);
|
||||
}
|
||||
|
||||
int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int inner_map_fd, int max_entries,
|
||||
__u32 map_flags)
|
||||
{
|
||||
return bpf_create_map_in_map_node(map_type, name, key_size,
|
||||
inner_map_fd, max_entries, map_flags,
|
||||
-1);
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts,
|
||||
.inner_map_fd = inner_map_fd,
|
||||
.map_flags = map_flags,
|
||||
);
|
||||
|
||||
return bpf_map_create(map_type, name, key_size, 4, max_entries, &opts);
|
||||
}
|
||||
|
||||
static void *
|
||||
@@ -219,58 +237,91 @@ alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
||||
return info;
|
||||
}
|
||||
|
||||
int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
||||
DEFAULT_VERSION(bpf_prog_load_v0_6_0, bpf_prog_load, LIBBPF_0.6.0)
|
||||
int bpf_prog_load_v0_6_0(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
const struct bpf_prog_load_opts *opts)
|
||||
{
|
||||
void *finfo = NULL, *linfo = NULL;
|
||||
const char *func_info, *line_info;
|
||||
__u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
|
||||
__u32 func_info_rec_size, line_info_rec_size;
|
||||
int fd, attempts;
|
||||
union bpf_attr attr;
|
||||
int fd;
|
||||
char *log_buf;
|
||||
|
||||
if (!load_attr->log_buf != !load_attr->log_buf_sz)
|
||||
if (!OPTS_VALID(opts, bpf_prog_load_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
if (load_attr->log_level > (4 | 2 | 1) || (load_attr->log_level && !load_attr->log_buf))
|
||||
attempts = OPTS_GET(opts, attempts, 0);
|
||||
if (attempts < 0)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (attempts == 0)
|
||||
attempts = PROG_LOAD_ATTEMPTS;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_type = load_attr->prog_type;
|
||||
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||
|
||||
if (load_attr->attach_prog_fd)
|
||||
attr.attach_prog_fd = load_attr->attach_prog_fd;
|
||||
attr.prog_type = prog_type;
|
||||
attr.expected_attach_type = OPTS_GET(opts, expected_attach_type, 0);
|
||||
|
||||
attr.prog_btf_fd = OPTS_GET(opts, prog_btf_fd, 0);
|
||||
attr.prog_flags = OPTS_GET(opts, prog_flags, 0);
|
||||
attr.prog_ifindex = OPTS_GET(opts, prog_ifindex, 0);
|
||||
attr.kern_version = OPTS_GET(opts, kern_version, 0);
|
||||
|
||||
if (prog_name)
|
||||
strncat(attr.prog_name, prog_name, sizeof(attr.prog_name) - 1);
|
||||
attr.license = ptr_to_u64(license);
|
||||
|
||||
if (insn_cnt > UINT_MAX)
|
||||
return libbpf_err(-E2BIG);
|
||||
|
||||
attr.insns = ptr_to_u64(insns);
|
||||
attr.insn_cnt = (__u32)insn_cnt;
|
||||
|
||||
attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
|
||||
attach_btf_obj_fd = OPTS_GET(opts, attach_btf_obj_fd, 0);
|
||||
|
||||
if (attach_prog_fd && attach_btf_obj_fd)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
attr.attach_btf_id = OPTS_GET(opts, attach_btf_id, 0);
|
||||
if (attach_prog_fd)
|
||||
attr.attach_prog_fd = attach_prog_fd;
|
||||
else
|
||||
attr.attach_btf_obj_fd = load_attr->attach_btf_obj_fd;
|
||||
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||
attr.attach_btf_obj_fd = attach_btf_obj_fd;
|
||||
|
||||
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||
attr.kern_version = load_attr->kern_version;
|
||||
log_buf = OPTS_GET(opts, log_buf, NULL);
|
||||
log_size = OPTS_GET(opts, log_size, 0);
|
||||
log_level = OPTS_GET(opts, log_level, 0);
|
||||
|
||||
attr.insn_cnt = (__u32)load_attr->insn_cnt;
|
||||
attr.insns = ptr_to_u64(load_attr->insns);
|
||||
attr.license = ptr_to_u64(load_attr->license);
|
||||
if (!!log_buf != !!log_size)
|
||||
return libbpf_err(-EINVAL);
|
||||
if (log_level > (4 | 2 | 1))
|
||||
return libbpf_err(-EINVAL);
|
||||
if (log_level && !log_buf)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
attr.log_level = load_attr->log_level;
|
||||
if (attr.log_level) {
|
||||
attr.log_buf = ptr_to_u64(load_attr->log_buf);
|
||||
attr.log_size = load_attr->log_buf_sz;
|
||||
}
|
||||
attr.log_level = log_level;
|
||||
attr.log_buf = ptr_to_u64(log_buf);
|
||||
attr.log_size = log_size;
|
||||
|
||||
attr.prog_btf_fd = load_attr->prog_btf_fd;
|
||||
attr.prog_flags = load_attr->prog_flags;
|
||||
func_info_rec_size = OPTS_GET(opts, func_info_rec_size, 0);
|
||||
func_info = OPTS_GET(opts, func_info, NULL);
|
||||
attr.func_info_rec_size = func_info_rec_size;
|
||||
attr.func_info = ptr_to_u64(func_info);
|
||||
attr.func_info_cnt = OPTS_GET(opts, func_info_cnt, 0);
|
||||
|
||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
attr.func_info_cnt = load_attr->func_info_cnt;
|
||||
attr.func_info = ptr_to_u64(load_attr->func_info);
|
||||
line_info_rec_size = OPTS_GET(opts, line_info_rec_size, 0);
|
||||
line_info = OPTS_GET(opts, line_info, NULL);
|
||||
attr.line_info_rec_size = line_info_rec_size;
|
||||
attr.line_info = ptr_to_u64(line_info);
|
||||
attr.line_info_cnt = OPTS_GET(opts, line_info_cnt, 0);
|
||||
|
||||
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||
attr.line_info_cnt = load_attr->line_info_cnt;
|
||||
attr.line_info = ptr_to_u64(load_attr->line_info);
|
||||
attr.fd_array = ptr_to_u64(load_attr->fd_array);
|
||||
attr.fd_array = ptr_to_u64(OPTS_GET(opts, fd_array, NULL));
|
||||
|
||||
if (load_attr->name)
|
||||
memcpy(attr.prog_name, load_attr->name,
|
||||
min(strlen(load_attr->name), (size_t)BPF_OBJ_NAME_LEN - 1));
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
@@ -280,11 +331,11 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
||||
*/
|
||||
while (errno == E2BIG && (!finfo || !linfo)) {
|
||||
if (!finfo && attr.func_info_cnt &&
|
||||
attr.func_info_rec_size < load_attr->func_info_rec_size) {
|
||||
attr.func_info_rec_size < func_info_rec_size) {
|
||||
/* try with corrected func info records */
|
||||
finfo = alloc_zero_tailing_info(load_attr->func_info,
|
||||
load_attr->func_info_cnt,
|
||||
load_attr->func_info_rec_size,
|
||||
finfo = alloc_zero_tailing_info(func_info,
|
||||
attr.func_info_cnt,
|
||||
func_info_rec_size,
|
||||
attr.func_info_rec_size);
|
||||
if (!finfo) {
|
||||
errno = E2BIG;
|
||||
@@ -292,13 +343,12 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
||||
}
|
||||
|
||||
attr.func_info = ptr_to_u64(finfo);
|
||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
attr.func_info_rec_size = func_info_rec_size;
|
||||
} else if (!linfo && attr.line_info_cnt &&
|
||||
attr.line_info_rec_size <
|
||||
load_attr->line_info_rec_size) {
|
||||
linfo = alloc_zero_tailing_info(load_attr->line_info,
|
||||
load_attr->line_info_cnt,
|
||||
load_attr->line_info_rec_size,
|
||||
attr.line_info_rec_size < line_info_rec_size) {
|
||||
linfo = alloc_zero_tailing_info(line_info,
|
||||
attr.line_info_cnt,
|
||||
line_info_rec_size,
|
||||
attr.line_info_rec_size);
|
||||
if (!linfo) {
|
||||
errno = E2BIG;
|
||||
@@ -306,26 +356,26 @@ int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr)
|
||||
}
|
||||
|
||||
attr.line_info = ptr_to_u64(linfo);
|
||||
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||
attr.line_info_rec_size = line_info_rec_size;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
||||
if (fd >= 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (load_attr->log_level || !load_attr->log_buf)
|
||||
if (log_level || !log_buf)
|
||||
goto done;
|
||||
|
||||
/* Try again with log */
|
||||
attr.log_buf = ptr_to_u64(load_attr->log_buf);
|
||||
attr.log_size = load_attr->log_buf_sz;
|
||||
log_buf[0] = 0;
|
||||
attr.log_buf = ptr_to_u64(log_buf);
|
||||
attr.log_size = log_size;
|
||||
attr.log_level = 1;
|
||||
load_attr->log_buf[0] = 0;
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), attempts);
|
||||
done:
|
||||
/* free() doesn't affect errno, so we don't need to restore it */
|
||||
free(finfo);
|
||||
@@ -333,17 +383,20 @@ done:
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
__attribute__((alias("bpf_load_program_xattr2")))
|
||||
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz)
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
|
||||
static int bpf_load_program_xattr2(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz)
|
||||
{
|
||||
struct bpf_prog_load_params p = {};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, p);
|
||||
|
||||
if (!load_attr || !log_buf != !log_buf_sz)
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
p.prog_type = load_attr->prog_type;
|
||||
p.expected_attach_type = load_attr->expected_attach_type;
|
||||
switch (p.prog_type) {
|
||||
switch (load_attr->prog_type) {
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
p.attach_btf_id = load_attr->attach_btf_id;
|
||||
@@ -357,12 +410,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
p.prog_ifindex = load_attr->prog_ifindex;
|
||||
p.kern_version = load_attr->kern_version;
|
||||
}
|
||||
p.insn_cnt = load_attr->insns_cnt;
|
||||
p.insns = load_attr->insns;
|
||||
p.license = load_attr->license;
|
||||
p.log_level = load_attr->log_level;
|
||||
p.log_buf = log_buf;
|
||||
p.log_buf_sz = log_buf_sz;
|
||||
p.log_size = log_buf_sz;
|
||||
p.prog_btf_fd = load_attr->prog_btf_fd;
|
||||
p.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
p.func_info_cnt = load_attr->func_info_cnt;
|
||||
@@ -370,10 +420,10 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
p.line_info_rec_size = load_attr->line_info_rec_size;
|
||||
p.line_info_cnt = load_attr->line_info_cnt;
|
||||
p.line_info = load_attr->line_info;
|
||||
p.name = load_attr->name;
|
||||
p.prog_flags = load_attr->prog_flags;
|
||||
|
||||
return libbpf__bpf_prog_load(&p);
|
||||
return bpf_prog_load(load_attr->prog_type, load_attr->name, load_attr->license,
|
||||
load_attr->insns, load_attr->insns_cnt, &p);
|
||||
}
|
||||
|
||||
int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||
@@ -392,7 +442,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||
load_attr.license = license;
|
||||
load_attr.kern_version = kern_version;
|
||||
|
||||
return bpf_load_program_xattr(&load_attr, log_buf, log_buf_sz);
|
||||
return bpf_load_program_xattr2(&load_attr, log_buf, log_buf_sz);
|
||||
}
|
||||
|
||||
int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||
@@ -415,7 +465,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||
attr.kern_version = kern_version;
|
||||
attr.prog_flags = prog_flags;
|
||||
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr));
|
||||
fd = sys_bpf_prog_load(&attr, sizeof(attr), PROG_LOAD_ATTEMPTS);
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -481,6 +531,7 @@ int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
||||
int bpf_map_lookup_and_delete_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;
|
||||
@@ -488,7 +539,8 @@ int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, _
|
||||
attr.value = ptr_to_u64(value);
|
||||
attr.flags = flags;
|
||||
|
||||
return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
||||
ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(ret);
|
||||
}
|
||||
|
||||
int bpf_map_delete_elem(int fd, const void *key)
|
||||
@@ -609,7 +661,7 @@ int bpf_obj_get(const char *pathname)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.pathname = ptr_to_u64((void *)pathname);
|
||||
|
||||
fd = sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_OBJ_GET, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -720,7 +772,7 @@ int bpf_link_create(int prog_fd, int target_fd,
|
||||
break;
|
||||
}
|
||||
proceed:
|
||||
fd = sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_LINK_CREATE, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -763,7 +815,7 @@ int bpf_iter_create(int link_fd)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.iter_create.link_fd = link_fd;
|
||||
|
||||
fd = sys_bpf(BPF_ITER_CREATE, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_ITER_CREATE, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -921,7 +973,7 @@ int bpf_prog_get_fd_by_id(__u32 id)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_id = id;
|
||||
|
||||
fd = sys_bpf(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_PROG_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -933,7 +985,7 @@ int bpf_map_get_fd_by_id(__u32 id)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.map_id = id;
|
||||
|
||||
fd = sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -945,7 +997,7 @@ int bpf_btf_get_fd_by_id(__u32 id)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.btf_id = id;
|
||||
|
||||
fd = sys_bpf(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -957,7 +1009,7 @@ int bpf_link_get_fd_by_id(__u32 id)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.link_id = id;
|
||||
|
||||
fd = sys_bpf(BPF_LINK_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_LINK_GET_FD_BY_ID, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -988,7 +1040,7 @@ int bpf_raw_tracepoint_open(const char *name, int prog_fd)
|
||||
attr.raw_tracepoint.name = ptr_to_u64(name);
|
||||
attr.raw_tracepoint.prog_fd = prog_fd;
|
||||
|
||||
fd = sys_bpf(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_RAW_TRACEPOINT_OPEN, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
@@ -1008,7 +1060,7 @@ retry:
|
||||
attr.btf_log_buf = ptr_to_u64(log_buf);
|
||||
}
|
||||
|
||||
fd = sys_bpf(BPF_BTF_LOAD, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_BTF_LOAD, &attr, sizeof(attr));
|
||||
|
||||
if (fd < 0 && !do_log && log_buf && log_buf_size) {
|
||||
do_log = true;
|
||||
@@ -1050,7 +1102,7 @@ int bpf_enable_stats(enum bpf_stats_type type)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.enable_stats.type = type;
|
||||
|
||||
fd = sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr));
|
||||
fd = sys_bpf_fd(BPF_ENABLE_STATS, &attr, sizeof(attr));
|
||||
return libbpf_err_errno(fd);
|
||||
}
|
||||
|
||||
|
||||
107
src/bpf.h
107
src/bpf.h
@@ -29,11 +29,36 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libbpf_common.h"
|
||||
#include "libbpf_legacy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct bpf_map_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
__u32 btf_fd;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
__u32 btf_vmlinux_value_type_id;
|
||||
|
||||
int inner_map_fd;
|
||||
int map_flags;
|
||||
__u64 map_extra;
|
||||
|
||||
int numa_node;
|
||||
int map_ifindex;
|
||||
};
|
||||
#define bpf_map_create_opts__last_field map_ifindex
|
||||
|
||||
LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
__u32 key_size,
|
||||
__u32 value_size,
|
||||
__u32 max_entries,
|
||||
const struct bpf_map_create_opts *opts);
|
||||
|
||||
struct bpf_create_map_attr {
|
||||
const char *name;
|
||||
enum bpf_map_type map_type;
|
||||
@@ -52,25 +77,95 @@ struct bpf_create_map_attr {
|
||||
};
|
||||
};
|
||||
|
||||
LIBBPF_API int
|
||||
bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size,
|
||||
int max_entries, __u32 map_flags, int node);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name,
|
||||
int key_size, int value_size,
|
||||
int max_entries, __u32 map_flags);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size,
|
||||
int value_size, int max_entries, __u32 map_flags);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type,
|
||||
const char *name, int key_size,
|
||||
int inner_map_fd, int max_entries,
|
||||
__u32 map_flags, int node);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_map_create() instead")
|
||||
LIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type,
|
||||
const char *name, int key_size,
|
||||
int inner_map_fd, int max_entries,
|
||||
__u32 map_flags);
|
||||
|
||||
struct bpf_prog_load_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
|
||||
/* libbpf can retry BPF_PROG_LOAD command if bpf() syscall returns
|
||||
* -EAGAIN. This field determines how many attempts libbpf has to
|
||||
* make. If not specified, libbpf will use default value of 5.
|
||||
*/
|
||||
int attempts;
|
||||
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
__u32 prog_btf_fd;
|
||||
__u32 prog_flags;
|
||||
__u32 prog_ifindex;
|
||||
__u32 kern_version;
|
||||
|
||||
__u32 attach_btf_id;
|
||||
__u32 attach_prog_fd;
|
||||
__u32 attach_btf_obj_fd;
|
||||
|
||||
const int *fd_array;
|
||||
|
||||
/* .BTF.ext func info data */
|
||||
const void *func_info;
|
||||
__u32 func_info_cnt;
|
||||
__u32 func_info_rec_size;
|
||||
|
||||
/* .BTF.ext line info data */
|
||||
const void *line_info;
|
||||
__u32 line_info_cnt;
|
||||
__u32 line_info_rec_size;
|
||||
|
||||
/* verifier log options */
|
||||
__u32 log_level;
|
||||
__u32 log_size;
|
||||
char *log_buf;
|
||||
};
|
||||
#define bpf_prog_load_opts__last_field log_buf
|
||||
|
||||
LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
const struct bpf_prog_load_opts *opts);
|
||||
/* this "specialization" should go away in libbpf 1.0 */
|
||||
LIBBPF_API int bpf_prog_load_v0_6_0(enum bpf_prog_type prog_type,
|
||||
const char *prog_name, const char *license,
|
||||
const struct bpf_insn *insns, size_t insn_cnt,
|
||||
const struct bpf_prog_load_opts *opts);
|
||||
|
||||
/* This is an elaborate way to not conflict with deprecated bpf_prog_load()
|
||||
* API, defined in libbpf.h. Once we hit libbpf 1.0, all this will be gone.
|
||||
* With this approach, if someone is calling bpf_prog_load() with
|
||||
* 4 arguments, they will use the deprecated API, which keeps backwards
|
||||
* compatibility (both source code and binary). If bpf_prog_load() is called
|
||||
* with 6 arguments, though, it gets redirected to __bpf_prog_load.
|
||||
* So looking forward to libbpf 1.0 when this hack will be gone and
|
||||
* __bpf_prog_load() will be called just bpf_prog_load().
|
||||
*/
|
||||
#ifndef bpf_prog_load
|
||||
#define bpf_prog_load(...) ___libbpf_overload(___bpf_prog_load, __VA_ARGS__)
|
||||
#define ___bpf_prog_load4(file, type, pobj, prog_fd) \
|
||||
bpf_prog_load_deprecated(file, type, pobj, prog_fd)
|
||||
#define ___bpf_prog_load6(prog_type, prog_name, license, insns, insn_cnt, opts) \
|
||||
bpf_prog_load(prog_type, prog_name, license, insns, insn_cnt, opts)
|
||||
#endif /* bpf_prog_load */
|
||||
|
||||
struct bpf_load_program_attr {
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
@@ -102,13 +197,15 @@ struct bpf_load_program_attr {
|
||||
|
||||
/* Recommend log buffer size */
|
||||
#define BPF_LOG_BUF_SIZE (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
|
||||
LIBBPF_API int
|
||||
bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
|
||||
const struct bpf_insn *insns, size_t insns_cnt,
|
||||
const char *license, __u32 kern_version,
|
||||
char *log_buf, size_t log_buf_sz);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_prog_load() instead")
|
||||
LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
|
||||
const struct bpf_insn *insns,
|
||||
size_t insns_cnt, __u32 prog_flags,
|
||||
|
||||
@@ -40,7 +40,7 @@ enum bpf_enum_value_kind {
|
||||
#define __CORE_RELO(src, field, info) \
|
||||
__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \
|
||||
bpf_probe_read_kernel( \
|
||||
(void *)dst, \
|
||||
|
||||
@@ -3,18 +3,26 @@
|
||||
#ifndef __BPF_GEN_INTERNAL_H
|
||||
#define __BPF_GEN_INTERNAL_H
|
||||
|
||||
#include "bpf.h"
|
||||
|
||||
struct ksym_relo_desc {
|
||||
const char *name;
|
||||
int kind;
|
||||
int insn_idx;
|
||||
bool is_weak;
|
||||
bool is_typeless;
|
||||
};
|
||||
|
||||
struct ksym_desc {
|
||||
const char *name;
|
||||
int ref;
|
||||
int kind;
|
||||
int off;
|
||||
union {
|
||||
/* used for kfunc */
|
||||
int off;
|
||||
/* used for typeless ksym */
|
||||
bool typeless;
|
||||
};
|
||||
int insn;
|
||||
};
|
||||
|
||||
@@ -39,17 +47,22 @@ struct bpf_gen {
|
||||
int nr_fd_array;
|
||||
};
|
||||
|
||||
void bpf_gen__init(struct bpf_gen *gen, int log_level);
|
||||
int bpf_gen__finish(struct bpf_gen *gen);
|
||||
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps);
|
||||
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps);
|
||||
void bpf_gen__free(struct bpf_gen *gen);
|
||||
void bpf_gen__load_btf(struct bpf_gen *gen, const void *raw_data, __u32 raw_size);
|
||||
void bpf_gen__map_create(struct bpf_gen *gen, 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_create(struct bpf_gen *gen,
|
||||
enum bpf_map_type map_type, const char *map_name,
|
||||
__u32 key_size, __u32 value_size, __u32 max_entries,
|
||||
struct bpf_map_create_opts *map_attr, int map_idx);
|
||||
void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||
enum bpf_prog_type prog_type, const char *prog_name,
|
||||
const char *license, struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *load_attr, int prog_idx);
|
||||
void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *value, __u32 value_size);
|
||||
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
|
||||
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak, int kind,
|
||||
int insn_idx);
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
bool is_typeless, int kind, int insn_idx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@ struct tcp_sock;
|
||||
struct tcp_timewait_sock;
|
||||
struct tcp_request_sock;
|
||||
struct udp6_sock;
|
||||
struct unix_sock;
|
||||
struct task_struct;
|
||||
struct __sk_buff;
|
||||
struct sk_msg_md;
|
||||
@@ -313,7 +314,7 @@ static long (*bpf_l4_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 fr
|
||||
* if the maximum number of tail calls has been reached for this
|
||||
* chain of programs. This limit is defined in the kernel by the
|
||||
* macro **MAX_TAIL_CALL_CNT** (not accessible to user space),
|
||||
* which is currently set to 32.
|
||||
* which is currently set to 33.
|
||||
*
|
||||
* Returns
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
@@ -4083,4 +4084,56 @@ static long (*bpf_get_branch_snapshot)(void *entries, __u32 size, __u64 flags) =
|
||||
*/
|
||||
static long (*bpf_trace_vprintk)(const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 177;
|
||||
|
||||
/*
|
||||
* bpf_skc_to_unix_sock
|
||||
*
|
||||
* Dynamically cast a *sk* pointer to a *unix_sock* pointer.
|
||||
*
|
||||
* Returns
|
||||
* *sk* if casting is valid, or **NULL** otherwise.
|
||||
*/
|
||||
static struct unix_sock *(*bpf_skc_to_unix_sock)(void *sk) = (void *) 178;
|
||||
|
||||
/*
|
||||
* bpf_kallsyms_lookup_name
|
||||
*
|
||||
* Get the address of a kernel symbol, returned in *res*. *res* is
|
||||
* set to 0 if the symbol is not found.
|
||||
*
|
||||
* Returns
|
||||
* On success, zero. On error, a negative value.
|
||||
*
|
||||
* **-EINVAL** if *flags* is not zero.
|
||||
*
|
||||
* **-EINVAL** if string *name* is not the same size as *name_sz*.
|
||||
*
|
||||
* **-ENOENT** if symbol is not found.
|
||||
*
|
||||
* **-EPERM** if caller does not have permission to obtain kernel address.
|
||||
*/
|
||||
static long (*bpf_kallsyms_lookup_name)(const char *name, int name_sz, int flags, __u64 *res) = (void *) 179;
|
||||
|
||||
/*
|
||||
* bpf_find_vma
|
||||
*
|
||||
* Find vma of *task* that contains *addr*, call *callback_fn*
|
||||
* function with *task*, *vma*, and *callback_ctx*.
|
||||
* 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 expected callback signature is
|
||||
*
|
||||
* long (\*callback_fn)(struct task_struct \*task, struct vm_area_struct \*vma, void \*callback_ctx);
|
||||
*
|
||||
*
|
||||
* Returns
|
||||
* 0 on success.
|
||||
* **-ENOENT** if *task->mm* is NULL, or no vma contains *addr*.
|
||||
* **-EBUSY** if failed to try lock mmap_lock.
|
||||
* **-EINVAL** for invalid **flags**.
|
||||
*/
|
||||
static long (*bpf_find_vma)(struct task_struct *task, __u64 addr, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 180;
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#elif defined(__TARGET_ARCH_sparc)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__TARGET_ARCH_riscv)
|
||||
#define bpf_target_riscv
|
||||
#define bpf_target_defined
|
||||
#else
|
||||
|
||||
/* Fall back to what the compiler says */
|
||||
@@ -48,6 +51,9 @@
|
||||
#elif defined(__sparc__)
|
||||
#define bpf_target_sparc
|
||||
#define bpf_target_defined
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define bpf_target_riscv
|
||||
#define bpf_target_defined
|
||||
#endif /* no compiler target */
|
||||
|
||||
#endif
|
||||
@@ -288,6 +294,32 @@ struct pt_regs;
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc)
|
||||
#endif
|
||||
|
||||
#elif defined(bpf_target_riscv)
|
||||
|
||||
struct pt_regs;
|
||||
#define PT_REGS_RV const volatile struct user_regs_struct
|
||||
#define PT_REGS_PARM1(x) (((PT_REGS_RV *)(x))->a0)
|
||||
#define PT_REGS_PARM2(x) (((PT_REGS_RV *)(x))->a1)
|
||||
#define PT_REGS_PARM3(x) (((PT_REGS_RV *)(x))->a2)
|
||||
#define PT_REGS_PARM4(x) (((PT_REGS_RV *)(x))->a3)
|
||||
#define PT_REGS_PARM5(x) (((PT_REGS_RV *)(x))->a4)
|
||||
#define PT_REGS_RET(x) (((PT_REGS_RV *)(x))->ra)
|
||||
#define PT_REGS_FP(x) (((PT_REGS_RV *)(x))->s5)
|
||||
#define PT_REGS_RC(x) (((PT_REGS_RV *)(x))->a5)
|
||||
#define PT_REGS_SP(x) (((PT_REGS_RV *)(x))->sp)
|
||||
#define PT_REGS_IP(x) (((PT_REGS_RV *)(x))->epc)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a0)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a1)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a2)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a3)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a4)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), ra)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), fp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a5)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), epc)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(bpf_target_powerpc)
|
||||
|
||||
319
src/btf.c
319
src/btf.c
@@ -57,7 +57,7 @@ struct btf {
|
||||
* representation is broken up into three independently allocated
|
||||
* memory regions to be able to modify them independently.
|
||||
* raw_data is nulled out at that point, but can be later allocated
|
||||
* and cached again if user calls btf__get_raw_data(), at which point
|
||||
* and cached again if user calls btf__raw_data(), at which point
|
||||
* raw_data will contain a contiguous copy of header, types, and
|
||||
* strings:
|
||||
*
|
||||
@@ -236,17 +236,23 @@ static int btf_parse_hdr(struct btf *btf)
|
||||
}
|
||||
btf_bswap_hdr(hdr);
|
||||
} else if (hdr->magic != BTF_MAGIC) {
|
||||
pr_debug("Invalid BTF magic:%x\n", hdr->magic);
|
||||
pr_debug("Invalid BTF magic: %x\n", hdr->magic);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
meta_left = btf->raw_size - sizeof(*hdr);
|
||||
if (meta_left < hdr->str_off + hdr->str_len) {
|
||||
pr_debug("Invalid BTF total size:%u\n", btf->raw_size);
|
||||
if (btf->raw_size < hdr->hdr_len) {
|
||||
pr_debug("BTF header len %u larger than data size %u\n",
|
||||
hdr->hdr_len, btf->raw_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr->type_off + hdr->type_len > hdr->str_off) {
|
||||
meta_left = btf->raw_size - hdr->hdr_len;
|
||||
if (meta_left < (long long)hdr->str_off + hdr->str_len) {
|
||||
pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
|
||||
pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
|
||||
hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
|
||||
return -EINVAL;
|
||||
@@ -293,6 +299,7 @@ static int btf_type_size(const struct btf_type *t)
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return base_size;
|
||||
case BTF_KIND_INT:
|
||||
return base_size + sizeof(__u32);
|
||||
@@ -309,8 +316,8 @@ static int btf_type_size(const struct btf_type *t)
|
||||
return base_size + sizeof(struct btf_var);
|
||||
case BTF_KIND_DATASEC:
|
||||
return base_size + vlen * sizeof(struct btf_var_secinfo);
|
||||
case BTF_KIND_TAG:
|
||||
return base_size + sizeof(struct btf_tag);
|
||||
case BTF_KIND_DECL_TAG:
|
||||
return base_size + sizeof(struct btf_decl_tag);
|
||||
default:
|
||||
pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||
return -EINVAL;
|
||||
@@ -343,6 +350,7 @@ static int btf_bswap_type_rest(struct btf_type *t)
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return 0;
|
||||
case BTF_KIND_INT:
|
||||
*(__u32 *)(t + 1) = bswap_32(*(__u32 *)(t + 1));
|
||||
@@ -383,8 +391,8 @@ static int btf_bswap_type_rest(struct btf_type *t)
|
||||
v->size = bswap_32(v->size);
|
||||
}
|
||||
return 0;
|
||||
case BTF_KIND_TAG:
|
||||
btf_tag(t)->component_idx = bswap_32(btf_tag(t)->component_idx);
|
||||
case BTF_KIND_DECL_TAG:
|
||||
btf_decl_tag(t)->component_idx = bswap_32(btf_decl_tag(t)->component_idx);
|
||||
return 0;
|
||||
default:
|
||||
pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||
@@ -435,6 +443,11 @@ __u32 btf__get_nr_types(const struct btf *btf)
|
||||
return btf->start_id + btf->nr_types - 1;
|
||||
}
|
||||
|
||||
__u32 btf__type_cnt(const struct btf *btf)
|
||||
{
|
||||
return btf->start_id + btf->nr_types;
|
||||
}
|
||||
|
||||
const struct btf *btf__base_btf(const struct btf *btf)
|
||||
{
|
||||
return btf->base_btf;
|
||||
@@ -466,8 +479,8 @@ static int determine_ptr_size(const struct btf *btf)
|
||||
if (btf->base_btf && btf->base_btf->ptr_sz > 0)
|
||||
return btf->base_btf->ptr_sz;
|
||||
|
||||
n = btf__get_nr_types(btf);
|
||||
for (i = 1; i <= n; i++) {
|
||||
n = btf__type_cnt(btf);
|
||||
for (i = 1; i < n; i++) {
|
||||
t = btf__type_by_id(btf, i);
|
||||
if (!btf_is_int(t))
|
||||
continue;
|
||||
@@ -527,9 +540,9 @@ int btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
|
||||
|
||||
static bool is_host_big_endian(void)
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return false;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
return true;
|
||||
#else
|
||||
# error "Unrecognized __BYTE_ORDER__"
|
||||
@@ -596,7 +609,8 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
type_id = t->type;
|
||||
break;
|
||||
case BTF_KIND_ARRAY:
|
||||
@@ -638,6 +652,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return btf__align_of(btf, t->type);
|
||||
case BTF_KIND_ARRAY:
|
||||
return btf__align_of(btf, btf_array(t)->type);
|
||||
@@ -684,12 +699,12 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
|
||||
|
||||
__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
|
||||
{
|
||||
__u32 i, nr_types = btf__get_nr_types(btf);
|
||||
__u32 i, nr_types = btf__type_cnt(btf);
|
||||
|
||||
if (!strcmp(type_name, "void"))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i <= nr_types; i++) {
|
||||
for (i = 1; i < nr_types; i++) {
|
||||
const struct btf_type *t = btf__type_by_id(btf, i);
|
||||
const char *name = btf__name_by_offset(btf, t->name_off);
|
||||
|
||||
@@ -703,12 +718,12 @@ __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
|
||||
static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
|
||||
const char *type_name, __u32 kind)
|
||||
{
|
||||
__u32 i, nr_types = btf__get_nr_types(btf);
|
||||
__u32 i, nr_types = btf__type_cnt(btf);
|
||||
|
||||
if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
|
||||
return 0;
|
||||
|
||||
for (i = start_id; i <= nr_types; i++) {
|
||||
for (i = start_id; i < nr_types; i++) {
|
||||
const struct btf_type *t = btf__type_by_id(btf, i);
|
||||
const char *name;
|
||||
|
||||
@@ -781,7 +796,7 @@ static struct btf *btf_new_empty(struct btf *base_btf)
|
||||
|
||||
if (base_btf) {
|
||||
btf->base_btf = base_btf;
|
||||
btf->start_id = btf__get_nr_types(base_btf) + 1;
|
||||
btf->start_id = btf__type_cnt(base_btf);
|
||||
btf->start_str_off = base_btf->hdr->str_len;
|
||||
}
|
||||
|
||||
@@ -831,7 +846,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
|
||||
|
||||
if (base_btf) {
|
||||
btf->base_btf = base_btf;
|
||||
btf->start_id = btf__get_nr_types(base_btf) + 1;
|
||||
btf->start_id = btf__type_cnt(base_btf);
|
||||
btf->start_str_off = base_btf->hdr->str_len;
|
||||
}
|
||||
|
||||
@@ -886,7 +901,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
|
||||
return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to open %s: %s\n", path, strerror(errno));
|
||||
@@ -1107,99 +1122,6 @@ struct btf *btf__parse_split(const char *path, struct btf *base_btf)
|
||||
return libbpf_ptr(btf_parse(path, base_btf, NULL));
|
||||
}
|
||||
|
||||
static int compare_vsi_off(const void *_a, const void *_b)
|
||||
{
|
||||
const struct btf_var_secinfo *a = _a;
|
||||
const struct btf_var_secinfo *b = _b;
|
||||
|
||||
return a->offset - b->offset;
|
||||
}
|
||||
|
||||
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
||||
struct btf_type *t)
|
||||
{
|
||||
__u32 size = 0, off = 0, i, vars = btf_vlen(t);
|
||||
const char *name = btf__name_by_offset(btf, t->name_off);
|
||||
const struct btf_type *t_var;
|
||||
struct btf_var_secinfo *vsi;
|
||||
const struct btf_var *var;
|
||||
int ret;
|
||||
|
||||
if (!name) {
|
||||
pr_debug("No name found in string section for DATASEC kind.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* .extern datasec size and var offsets were set correctly during
|
||||
* extern collection step, so just skip straight to sorting variables
|
||||
*/
|
||||
if (t->size)
|
||||
goto sort_vars;
|
||||
|
||||
ret = bpf_object__section_size(obj, name, &size);
|
||||
if (ret || !size || (t->size && t->size != size)) {
|
||||
pr_debug("Invalid size for section %s: %u bytes\n", name, size);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
t->size = size;
|
||||
|
||||
for (i = 0, vsi = btf_var_secinfos(t); i < vars; i++, vsi++) {
|
||||
t_var = btf__type_by_id(btf, vsi->type);
|
||||
var = btf_var(t_var);
|
||||
|
||||
if (!btf_is_var(t_var)) {
|
||||
pr_debug("Non-VAR type seen in section %s\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (var->linkage == BTF_VAR_STATIC)
|
||||
continue;
|
||||
|
||||
name = btf__name_by_offset(btf, t_var->name_off);
|
||||
if (!name) {
|
||||
pr_debug("No name found in string section for VAR kind\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = bpf_object__variable_offset(obj, name, &off);
|
||||
if (ret) {
|
||||
pr_debug("No offset found in symbol table for VAR %s\n",
|
||||
name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
vsi->offset = off;
|
||||
}
|
||||
|
||||
sort_vars:
|
||||
qsort(btf_var_secinfos(t), vars, sizeof(*vsi), compare_vsi_off);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
|
||||
{
|
||||
int err = 0;
|
||||
__u32 i;
|
||||
|
||||
for (i = 1; i <= btf->nr_types; i++) {
|
||||
struct btf_type *t = btf_type_by_id(btf, i);
|
||||
|
||||
/* Loader needs to fix up some of the things compiler
|
||||
* couldn't get its hands on while emitting BTF. This
|
||||
* is section size and global variable offset. We use
|
||||
* the info from the ELF itself for this purpose.
|
||||
*/
|
||||
if (btf_is_datasec(t)) {
|
||||
err = btf_fixup_datasec(obj, btf, t);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian);
|
||||
|
||||
int btf__load_into_kernel(struct btf *btf)
|
||||
@@ -1317,7 +1239,7 @@ err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *btf__get_raw_data(const struct btf *btf_ro, __u32 *size)
|
||||
const void *btf__raw_data(const struct btf *btf_ro, __u32 *size)
|
||||
{
|
||||
struct btf *btf = (struct btf *)btf_ro;
|
||||
__u32 data_sz;
|
||||
@@ -1325,7 +1247,7 @@ const void *btf__get_raw_data(const struct btf *btf_ro, __u32 *size)
|
||||
|
||||
data = btf_get_raw_data(btf, &data_sz, btf->swapped_endian);
|
||||
if (!data)
|
||||
return errno = -ENOMEM, NULL;
|
||||
return errno = ENOMEM, NULL;
|
||||
|
||||
btf->raw_size = data_sz;
|
||||
if (btf->swapped_endian)
|
||||
@@ -1336,6 +1258,9 @@ const void *btf__get_raw_data(const struct btf *btf_ro, __u32 *size)
|
||||
return data;
|
||||
}
|
||||
|
||||
__attribute__((alias("btf__raw_data")))
|
||||
const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||
|
||||
const char *btf__str_by_offset(const struct btf *btf, __u32 offset)
|
||||
{
|
||||
if (offset < btf->start_str_off)
|
||||
@@ -1744,7 +1669,7 @@ int btf__add_btf(struct btf *btf, const struct btf *src_btf)
|
||||
old_strs_len = btf->hdr->str_len;
|
||||
|
||||
data_sz = src_btf->hdr->type_len;
|
||||
cnt = btf__get_nr_types(src_btf);
|
||||
cnt = btf__type_cnt(src_btf) - 1;
|
||||
|
||||
/* pre-allocate enough memory for new types */
|
||||
t = btf_add_type_mem(btf, data_sz);
|
||||
@@ -2061,7 +1986,7 @@ int btf__add_union(struct btf *btf, const char *name, __u32 byte_sz)
|
||||
|
||||
static struct btf_type *btf_last_type(struct btf *btf)
|
||||
{
|
||||
return btf_type_by_id(btf, btf__get_nr_types(btf));
|
||||
return btf_type_by_id(btf, btf__type_cnt(btf) - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2314,6 +2239,22 @@ int btf__add_restrict(struct btf *btf, int ref_type_id)
|
||||
return btf_add_ref_kind(btf, BTF_KIND_RESTRICT, NULL, ref_type_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append new BTF_KIND_TYPE_TAG type with:
|
||||
* - *value*, non-empty/non-NULL tag value;
|
||||
* - *ref_type_id* - referenced type ID, it might not exist yet;
|
||||
* Returns:
|
||||
* - >0, type ID of newly added BTF type;
|
||||
* - <0, on error.
|
||||
*/
|
||||
int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id)
|
||||
{
|
||||
if (!value|| !value[0])
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
return btf_add_ref_kind(btf, BTF_KIND_TYPE_TAG, value, ref_type_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append new BTF_KIND_FUNC type with:
|
||||
* - *name*, non-empty/non-NULL name;
|
||||
@@ -2569,7 +2510,7 @@ int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __
|
||||
}
|
||||
|
||||
/*
|
||||
* Append new BTF_KIND_TAG type with:
|
||||
* Append new BTF_KIND_DECL_TAG type with:
|
||||
* - *value* - non-empty/non-NULL string;
|
||||
* - *ref_type_id* - referenced type ID, it might not exist yet;
|
||||
* - *component_idx* - -1 for tagging reference type, otherwise struct/union
|
||||
@@ -2578,7 +2519,7 @@ int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __
|
||||
* - >0, type ID of newly added BTF type;
|
||||
* - <0, on error.
|
||||
*/
|
||||
int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
int component_idx)
|
||||
{
|
||||
struct btf_type *t;
|
||||
@@ -2593,7 +2534,7 @@ int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
if (btf_ensure_modifiable(btf))
|
||||
return libbpf_err(-ENOMEM);
|
||||
|
||||
sz = sizeof(struct btf_type) + sizeof(struct btf_tag);
|
||||
sz = sizeof(struct btf_type) + sizeof(struct btf_decl_tag);
|
||||
t = btf_add_type_mem(btf, sz);
|
||||
if (!t)
|
||||
return libbpf_err(-ENOMEM);
|
||||
@@ -2603,9 +2544,9 @@ int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
return value_off;
|
||||
|
||||
t->name_off = value_off;
|
||||
t->info = btf_type_info(BTF_KIND_TAG, 0, false);
|
||||
t->info = btf_type_info(BTF_KIND_DECL_TAG, 0, false);
|
||||
t->type = ref_type_id;
|
||||
btf_tag(t)->component_idx = component_idx;
|
||||
btf_decl_tag(t)->component_idx = component_idx;
|
||||
|
||||
return btf_commit_type(btf, sz);
|
||||
}
|
||||
@@ -2790,15 +2731,11 @@ void btf_ext__free(struct btf_ext *btf_ext)
|
||||
free(btf_ext);
|
||||
}
|
||||
|
||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
||||
struct btf_ext *btf_ext__new(const __u8 *data, __u32 size)
|
||||
{
|
||||
struct btf_ext *btf_ext;
|
||||
int err;
|
||||
|
||||
err = btf_ext_parse_hdr(data, size);
|
||||
if (err)
|
||||
return libbpf_err_ptr(err);
|
||||
|
||||
btf_ext = calloc(1, sizeof(struct btf_ext));
|
||||
if (!btf_ext)
|
||||
return libbpf_err_ptr(-ENOMEM);
|
||||
@@ -2811,6 +2748,10 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
||||
}
|
||||
memcpy(btf_ext->data, data, size);
|
||||
|
||||
err = btf_ext_parse_hdr(btf_ext->data, size);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
@@ -2925,8 +2866,7 @@ __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext)
|
||||
|
||||
struct btf_dedup;
|
||||
|
||||
static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const struct btf_dedup_opts *opts);
|
||||
static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
static void btf_dedup_free(struct btf_dedup *d);
|
||||
static int btf_dedup_prep(struct btf_dedup *d);
|
||||
static int btf_dedup_strings(struct btf_dedup *d);
|
||||
@@ -3073,19 +3013,26 @@ static int btf_dedup_remap_types(struct btf_dedup *d);
|
||||
* deduplicating structs/unions is described in greater details in comments for
|
||||
* `btf_dedup_is_equiv` function.
|
||||
*/
|
||||
int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const struct btf_dedup_opts *opts)
|
||||
|
||||
DEFAULT_VERSION(btf__dedup_v0_6_0, btf__dedup, LIBBPF_0.6.0)
|
||||
int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts)
|
||||
{
|
||||
struct btf_dedup *d = btf_dedup_new(btf, btf_ext, opts);
|
||||
struct btf_dedup *d;
|
||||
int err;
|
||||
|
||||
if (!OPTS_VALID(opts, btf_dedup_opts))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
d = btf_dedup_new(btf, opts);
|
||||
if (IS_ERR(d)) {
|
||||
pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d));
|
||||
return libbpf_err(-EINVAL);
|
||||
}
|
||||
|
||||
if (btf_ensure_modifiable(btf))
|
||||
return libbpf_err(-ENOMEM);
|
||||
if (btf_ensure_modifiable(btf)) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = btf_dedup_prep(d);
|
||||
if (err) {
|
||||
@@ -3128,6 +3075,19 @@ done:
|
||||
return libbpf_err(err);
|
||||
}
|
||||
|
||||
COMPAT_VERSION(bpf__dedup_deprecated, btf__dedup, LIBBPF_0.0.2)
|
||||
int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *unused_opts)
|
||||
{
|
||||
LIBBPF_OPTS(btf_dedup_opts, opts, .btf_ext = btf_ext);
|
||||
|
||||
if (unused_opts) {
|
||||
pr_warn("please use new version of btf__dedup() that supports options\n");
|
||||
return libbpf_err(-ENOTSUP);
|
||||
}
|
||||
|
||||
return btf__dedup(btf, &opts);
|
||||
}
|
||||
|
||||
#define BTF_UNPROCESSED_ID ((__u32)-1)
|
||||
#define BTF_IN_PROGRESS_ID ((__u32)-2)
|
||||
|
||||
@@ -3240,8 +3200,7 @@ static bool btf_dedup_equal_fn(const void *k1, const void *k2, void *ctx)
|
||||
return k1 == k2;
|
||||
}
|
||||
|
||||
static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const struct btf_dedup_opts *opts)
|
||||
static struct btf_dedup *btf_dedup_new(struct btf *btf, const struct btf_dedup_opts *opts)
|
||||
{
|
||||
struct btf_dedup *d = calloc(1, sizeof(struct btf_dedup));
|
||||
hashmap_hash_fn hash_fn = btf_dedup_identity_hash_fn;
|
||||
@@ -3250,13 +3209,11 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
||||
if (!d)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
d->opts.dont_resolve_fwds = opts && opts->dont_resolve_fwds;
|
||||
/* dedup_table_size is now used only to force collisions in tests */
|
||||
if (opts && opts->dedup_table_size == 1)
|
||||
if (OPTS_GET(opts, force_collisions, false))
|
||||
hash_fn = btf_dedup_collision_hash_fn;
|
||||
|
||||
d->btf = btf;
|
||||
d->btf_ext = btf_ext;
|
||||
d->btf_ext = OPTS_GET(opts, btf_ext, NULL);
|
||||
|
||||
d->dedup_table = hashmap__new(hash_fn, btf_dedup_equal_fn, NULL);
|
||||
if (IS_ERR(d->dedup_table)) {
|
||||
@@ -3265,7 +3222,7 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
||||
goto done;
|
||||
}
|
||||
|
||||
type_cnt = btf__get_nr_types(btf) + 1;
|
||||
type_cnt = btf__type_cnt(btf);
|
||||
d->map = malloc(sizeof(__u32) * type_cnt);
|
||||
if (!d->map) {
|
||||
err = -ENOMEM;
|
||||
@@ -3427,7 +3384,7 @@ static bool btf_equal_common(struct btf_type *t1, struct btf_type *t2)
|
||||
}
|
||||
|
||||
/* Calculate type signature hash of INT or TAG. */
|
||||
static long btf_hash_int_tag(struct btf_type *t)
|
||||
static long btf_hash_int_decl_tag(struct btf_type *t)
|
||||
{
|
||||
__u32 info = *(__u32 *)(t + 1);
|
||||
long h;
|
||||
@@ -3520,8 +3477,8 @@ static long btf_hash_struct(struct btf_type *t)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check structural compatibility of two FUNC_PROTOs, ignoring referenced type
|
||||
* IDs. This check is performed during type graph equivalence check and
|
||||
* Check structural compatibility of two STRUCTs/UNIONs, ignoring referenced
|
||||
* type IDs. This check is performed during type graph equivalence check and
|
||||
* referenced types equivalence is checked separately.
|
||||
*/
|
||||
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
||||
@@ -3702,11 +3659,12 @@ static int btf_dedup_prep(struct btf_dedup *d)
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
h = btf_hash_common(t);
|
||||
break;
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_TAG:
|
||||
h = btf_hash_int_tag(t);
|
||||
case BTF_KIND_DECL_TAG:
|
||||
h = btf_hash_int_decl_tag(t);
|
||||
break;
|
||||
case BTF_KIND_ENUM:
|
||||
h = btf_hash_enum(t);
|
||||
@@ -3761,11 +3719,12 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_DATASEC:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return 0;
|
||||
|
||||
case BTF_KIND_INT:
|
||||
h = btf_hash_int_tag(t);
|
||||
h = btf_hash_int_decl_tag(t);
|
||||
for_each_dedup_cand(d, hash_entry, h) {
|
||||
cand_id = (__u32)(long)hash_entry->value;
|
||||
cand = btf_type_by_id(d->btf, cand_id);
|
||||
@@ -3785,8 +3744,6 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
||||
new_id = cand_id;
|
||||
break;
|
||||
}
|
||||
if (d->opts.dont_resolve_fwds)
|
||||
continue;
|
||||
if (btf_compat_enum(t, cand)) {
|
||||
if (btf_is_enum_fwd(t)) {
|
||||
/* resolve fwd to full enum */
|
||||
@@ -3894,6 +3851,31 @@ static int btf_dedup_identical_arrays(struct btf_dedup *d, __u32 id1, __u32 id2)
|
||||
return btf_equal_array(t1, t2);
|
||||
}
|
||||
|
||||
/* Check if given two types are identical STRUCT/UNION definitions */
|
||||
static bool btf_dedup_identical_structs(struct btf_dedup *d, __u32 id1, __u32 id2)
|
||||
{
|
||||
const struct btf_member *m1, *m2;
|
||||
struct btf_type *t1, *t2;
|
||||
int n, i;
|
||||
|
||||
t1 = btf_type_by_id(d->btf, id1);
|
||||
t2 = btf_type_by_id(d->btf, id2);
|
||||
|
||||
if (!btf_is_composite(t1) || btf_kind(t1) != btf_kind(t2))
|
||||
return false;
|
||||
|
||||
if (!btf_shallow_equal_struct(t1, t2))
|
||||
return false;
|
||||
|
||||
m1 = btf_members(t1);
|
||||
m2 = btf_members(t2);
|
||||
for (i = 0, n = btf_vlen(t1); i < n; i++, m1++, m2++) {
|
||||
if (m1->type != m2->type)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check equivalence of BTF type graph formed by candidate struct/union (we'll
|
||||
* call it "candidate graph" in this description for brevity) to a type graph
|
||||
@@ -4005,6 +3987,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
|
||||
hypot_type_id = d->hypot_map[canon_id];
|
||||
if (hypot_type_id <= BTF_MAX_NR_TYPES) {
|
||||
if (hypot_type_id == cand_id)
|
||||
return 1;
|
||||
/* In some cases compiler will generate different DWARF types
|
||||
* for *identical* array type definitions and use them for
|
||||
* different fields within the *same* struct. This breaks type
|
||||
@@ -4013,8 +3997,18 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
* types within a single CU. So work around that by explicitly
|
||||
* allowing identical array types here.
|
||||
*/
|
||||
return hypot_type_id == cand_id ||
|
||||
btf_dedup_identical_arrays(d, hypot_type_id, cand_id);
|
||||
if (btf_dedup_identical_arrays(d, hypot_type_id, cand_id))
|
||||
return 1;
|
||||
/* It turns out that similar situation can happen with
|
||||
* struct/union sometimes, sigh... Handle the case where
|
||||
* structs/unions are exactly the same, down to the referenced
|
||||
* type IDs. Anything more complicated (e.g., if referenced
|
||||
* types are different, but equivalent) is *way more*
|
||||
* complicated and requires a many-to-many equivalence mapping.
|
||||
*/
|
||||
if (btf_dedup_identical_structs(d, hypot_type_id, cand_id))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (btf_dedup_hypot_map_add(d, canon_id, cand_id))
|
||||
@@ -4029,8 +4023,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
return 0;
|
||||
|
||||
/* FWD <--> STRUCT/UNION equivalence check, if enabled */
|
||||
if (!d->opts.dont_resolve_fwds
|
||||
&& (cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
|
||||
if ((cand_kind == BTF_KIND_FWD || canon_kind == BTF_KIND_FWD)
|
||||
&& cand_kind != canon_kind) {
|
||||
__u16 real_kind;
|
||||
__u16 fwd_kind;
|
||||
@@ -4056,10 +4049,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
return btf_equal_int_tag(cand_type, canon_type);
|
||||
|
||||
case BTF_KIND_ENUM:
|
||||
if (d->opts.dont_resolve_fwds)
|
||||
return btf_equal_enum(cand_type, canon_type);
|
||||
else
|
||||
return btf_compat_enum(cand_type, canon_type);
|
||||
return btf_compat_enum(cand_type, canon_type);
|
||||
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_FLOAT:
|
||||
@@ -4071,6 +4061,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
if (cand_type->info != canon_type->info)
|
||||
return 0;
|
||||
return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
||||
@@ -4366,6 +4357,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
ref_type_id = btf_dedup_ref_type(d, t->type);
|
||||
if (ref_type_id < 0)
|
||||
return ref_type_id;
|
||||
@@ -4382,13 +4374,13 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
||||
}
|
||||
break;
|
||||
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
ref_type_id = btf_dedup_ref_type(d, t->type);
|
||||
if (ref_type_id < 0)
|
||||
return ref_type_id;
|
||||
t->type = ref_type_id;
|
||||
|
||||
h = btf_hash_int_tag(t);
|
||||
h = btf_hash_int_decl_tag(t);
|
||||
for_each_dedup_cand(d, hash_entry, h) {
|
||||
cand_id = (__u32)(long)hash_entry->value;
|
||||
cand = btf_type_by_id(d->btf, cand_id);
|
||||
@@ -4671,7 +4663,8 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return visit(&t->type, ctx);
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
|
||||
99
src/btf.h
99
src/btf.h
@@ -123,6 +123,7 @@ LIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *b
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_from_kernel_by_id instead")
|
||||
LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "intended for internal libbpf use only")
|
||||
LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use btf__load_into_kernel instead")
|
||||
LIBBPF_API int btf__load(struct btf *btf);
|
||||
@@ -131,7 +132,9 @@ LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
|
||||
const char *type_name);
|
||||
LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
|
||||
const char *type_name, __u32 kind);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use btf__type_cnt() instead; note that btf__get_nr_types() == btf__type_cnt() - 1")
|
||||
LIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);
|
||||
LIBBPF_API __u32 btf__type_cnt(const struct btf *btf);
|
||||
LIBBPF_API const struct btf *btf__base_btf(const struct btf *btf);
|
||||
LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,
|
||||
__u32 id);
|
||||
@@ -144,7 +147,9 @@ LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||
LIBBPF_API int btf__align_of(const struct btf *btf, __u32 id);
|
||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||
LIBBPF_API void btf__set_fd(struct btf *btf, int fd);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use btf__raw_data() instead")
|
||||
LIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);
|
||||
LIBBPF_API const void *btf__raw_data(const struct btf *btf, __u32 *size);
|
||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_API int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
||||
@@ -152,7 +157,7 @@ LIBBPF_API int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
||||
__u32 expected_value_size,
|
||||
__u32 *key_type_id, __u32 *value_type_id);
|
||||
|
||||
LIBBPF_API struct btf_ext *btf_ext__new(__u8 *data, __u32 size);
|
||||
LIBBPF_API struct btf_ext *btf_ext__new(const __u8 *data, __u32 size);
|
||||
LIBBPF_API void btf_ext__free(struct btf_ext *btf_ext);
|
||||
LIBBPF_API const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext,
|
||||
__u32 *size);
|
||||
@@ -222,6 +227,7 @@ LIBBPF_API int btf__add_typedef(struct btf *btf, const char *name, int ref_type_
|
||||
LIBBPF_API int btf__add_volatile(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_const(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_restrict(struct btf *btf, int ref_type_id);
|
||||
LIBBPF_API int btf__add_type_tag(struct btf *btf, const char *value, int ref_type_id);
|
||||
|
||||
/* func and func_proto construction APIs */
|
||||
LIBBPF_API int btf__add_func(struct btf *btf, const char *name,
|
||||
@@ -236,29 +242,84 @@ LIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,
|
||||
__u32 offset, __u32 byte_sz);
|
||||
|
||||
/* tag construction API */
|
||||
LIBBPF_API int btf__add_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
LIBBPF_API int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id,
|
||||
int component_idx);
|
||||
|
||||
struct btf_dedup_opts {
|
||||
unsigned int dedup_table_size;
|
||||
bool dont_resolve_fwds;
|
||||
size_t sz;
|
||||
/* optional .BTF.ext info to dedup along the main BTF info */
|
||||
struct btf_ext *btf_ext;
|
||||
/* force hash collisions (used for testing) */
|
||||
bool force_collisions;
|
||||
size_t :0;
|
||||
};
|
||||
#define btf_dedup_opts__last_field force_collisions
|
||||
|
||||
LIBBPF_API int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const struct btf_dedup_opts *opts);
|
||||
LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
|
||||
LIBBPF_API int btf__dedup_v0_6_0(struct btf *btf, const struct btf_dedup_opts *opts);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use btf__dedup() instead")
|
||||
LIBBPF_API int btf__dedup_deprecated(struct btf *btf, struct btf_ext *btf_ext, const void *opts);
|
||||
#define btf__dedup(...) ___libbpf_overload(___btf_dedup, __VA_ARGS__)
|
||||
#define ___btf_dedup3(btf, btf_ext, opts) btf__dedup_deprecated(btf, btf_ext, opts)
|
||||
#define ___btf_dedup2(btf, opts) btf__dedup(btf, opts)
|
||||
|
||||
struct btf_dump;
|
||||
|
||||
struct btf_dump_opts {
|
||||
void *ctx;
|
||||
union {
|
||||
size_t sz;
|
||||
void *ctx; /* DEPRECATED: will be gone in v1.0 */
|
||||
};
|
||||
};
|
||||
|
||||
typedef void (*btf_dump_printf_fn_t)(void *ctx, const char *fmt, va_list args);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn);
|
||||
btf_dump_printf_fn_t printf_fn,
|
||||
void *ctx,
|
||||
const struct btf_dump_opts *opts);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new_v0_6_0(const struct btf *btf,
|
||||
btf_dump_printf_fn_t printf_fn,
|
||||
void *ctx,
|
||||
const struct btf_dump_opts *opts);
|
||||
|
||||
LIBBPF_API struct btf_dump *btf_dump__new_deprecated(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn);
|
||||
|
||||
/* Choose either btf_dump__new() or btf_dump__new_deprecated() based on the
|
||||
* type of 4th argument. If it's btf_dump's print callback, use deprecated
|
||||
* API; otherwise, choose the new btf_dump__new(). ___libbpf_override()
|
||||
* doesn't work here because both variants have 4 input arguments.
|
||||
*
|
||||
* (void *) casts are necessary to avoid compilation warnings about type
|
||||
* mismatches, because even though __builtin_choose_expr() only ever evaluates
|
||||
* one side the other side still has to satisfy type constraints (this is
|
||||
* compiler implementation limitation which might be lifted eventually,
|
||||
* according to the documentation). So passing struct btf_ext in place of
|
||||
* btf_dump_printf_fn_t would be generating compilation warning. Casting to
|
||||
* void * avoids this issue.
|
||||
*
|
||||
* Also, two type compatibility checks for a function and function pointer are
|
||||
* required because passing function reference into btf_dump__new() as
|
||||
* btf_dump__new(..., my_callback, ...) and as btf_dump__new(...,
|
||||
* &my_callback, ...) (not explicit ampersand in the latter case) actually
|
||||
* differs as far as __builtin_types_compatible_p() is concerned. Thus two
|
||||
* checks are combined to detect callback argument.
|
||||
*
|
||||
* The rest works just like in case of ___libbpf_override() usage with symbol
|
||||
* versioning.
|
||||
*/
|
||||
#define btf_dump__new(a1, a2, a3, a4) __builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(a4), btf_dump_printf_fn_t) || \
|
||||
__builtin_types_compatible_p(typeof(a4), void(void *, const char *, va_list)), \
|
||||
btf_dump__new_deprecated((void *)a1, (void *)a2, (void *)a3, (void *)a4), \
|
||||
btf_dump__new((void *)a1, (void *)a2, (void *)a3, (void *)a4))
|
||||
|
||||
LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
||||
|
||||
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
||||
@@ -398,7 +459,8 @@ static inline bool btf_is_mod(const struct btf_type *t)
|
||||
|
||||
return kind == BTF_KIND_VOLATILE ||
|
||||
kind == BTF_KIND_CONST ||
|
||||
kind == BTF_KIND_RESTRICT;
|
||||
kind == BTF_KIND_RESTRICT ||
|
||||
kind == BTF_KIND_TYPE_TAG;
|
||||
}
|
||||
|
||||
static inline bool btf_is_func(const struct btf_type *t)
|
||||
@@ -426,9 +488,14 @@ static inline bool btf_is_float(const struct btf_type *t)
|
||||
return btf_kind(t) == BTF_KIND_FLOAT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_tag(const struct btf_type *t)
|
||||
static inline bool btf_is_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_TAG;
|
||||
return btf_kind(t) == BTF_KIND_DECL_TAG;
|
||||
}
|
||||
|
||||
static inline bool btf_is_type_tag(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_TYPE_TAG;
|
||||
}
|
||||
|
||||
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||
@@ -499,10 +566,10 @@ btf_var_secinfos(const struct btf_type *t)
|
||||
return (struct btf_var_secinfo *)(t + 1);
|
||||
}
|
||||
|
||||
struct btf_tag;
|
||||
static inline struct btf_tag *btf_tag(const struct btf_type *t)
|
||||
struct btf_decl_tag;
|
||||
static inline struct btf_decl_tag *btf_decl_tag(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_tag *)(t + 1);
|
||||
return (struct btf_decl_tag *)(t + 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
106
src/btf_dump.c
106
src/btf_dump.c
@@ -77,9 +77,8 @@ struct btf_dump_data {
|
||||
|
||||
struct btf_dump {
|
||||
const struct btf *btf;
|
||||
const struct btf_ext *btf_ext;
|
||||
btf_dump_printf_fn_t printf_fn;
|
||||
struct btf_dump_opts opts;
|
||||
void *cb_ctx;
|
||||
int ptr_sz;
|
||||
bool strip_mods;
|
||||
bool skip_anon_defs;
|
||||
@@ -138,29 +137,32 @@ static void btf_dump_printf(const struct btf_dump *d, const char *fmt, ...)
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
d->printf_fn(d->opts.ctx, fmt, args);
|
||||
d->printf_fn(d->cb_ctx, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int btf_dump_mark_referenced(struct btf_dump *d);
|
||||
static int btf_dump_resize(struct btf_dump *d);
|
||||
|
||||
struct btf_dump *btf_dump__new(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn)
|
||||
DEFAULT_VERSION(btf_dump__new_v0_6_0, btf_dump__new, LIBBPF_0.6.0)
|
||||
struct btf_dump *btf_dump__new_v0_6_0(const struct btf *btf,
|
||||
btf_dump_printf_fn_t printf_fn,
|
||||
void *ctx,
|
||||
const struct btf_dump_opts *opts)
|
||||
{
|
||||
struct btf_dump *d;
|
||||
int err;
|
||||
|
||||
if (!printf_fn)
|
||||
return libbpf_err_ptr(-EINVAL);
|
||||
|
||||
d = calloc(1, sizeof(struct btf_dump));
|
||||
if (!d)
|
||||
return libbpf_err_ptr(-ENOMEM);
|
||||
|
||||
d->btf = btf;
|
||||
d->btf_ext = btf_ext;
|
||||
d->printf_fn = printf_fn;
|
||||
d->opts.ctx = opts ? opts->ctx : NULL;
|
||||
d->cb_ctx = ctx;
|
||||
d->ptr_sz = btf__pointer_size(btf) ? : sizeof(void *);
|
||||
|
||||
d->type_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
|
||||
@@ -186,9 +188,20 @@ err:
|
||||
return libbpf_err_ptr(err);
|
||||
}
|
||||
|
||||
COMPAT_VERSION(btf_dump__new_deprecated, btf_dump__new, LIBBPF_0.0.4)
|
||||
struct btf_dump *btf_dump__new_deprecated(const struct btf *btf,
|
||||
const struct btf_ext *btf_ext,
|
||||
const struct btf_dump_opts *opts,
|
||||
btf_dump_printf_fn_t printf_fn)
|
||||
{
|
||||
if (!printf_fn)
|
||||
return libbpf_err_ptr(-EINVAL);
|
||||
return btf_dump__new_v0_6_0(btf, printf_fn, opts ? opts->ctx : NULL, opts);
|
||||
}
|
||||
|
||||
static int btf_dump_resize(struct btf_dump *d)
|
||||
{
|
||||
int err, last_id = btf__get_nr_types(d->btf);
|
||||
int err, last_id = btf__type_cnt(d->btf) - 1;
|
||||
|
||||
if (last_id <= d->last_id)
|
||||
return 0;
|
||||
@@ -262,7 +275,7 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
if (id > btf__get_nr_types(d->btf))
|
||||
if (id >= btf__type_cnt(d->btf))
|
||||
return libbpf_err(-EINVAL);
|
||||
|
||||
err = btf_dump_resize(d);
|
||||
@@ -294,11 +307,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
||||
*/
|
||||
static int btf_dump_mark_referenced(struct btf_dump *d)
|
||||
{
|
||||
int i, j, n = btf__get_nr_types(d->btf);
|
||||
int i, j, n = btf__type_cnt(d->btf);
|
||||
const struct btf_type *t;
|
||||
__u16 vlen;
|
||||
|
||||
for (i = d->last_id + 1; i <= n; i++) {
|
||||
for (i = d->last_id + 1; i < n; i++) {
|
||||
t = btf__type_by_id(d->btf, i);
|
||||
vlen = btf_vlen(t);
|
||||
|
||||
@@ -316,7 +329,8 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
d->type_states[t->type].referenced = 1;
|
||||
break;
|
||||
|
||||
@@ -560,6 +574,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
return btf_dump_order_type(d, t->type, through_ptr);
|
||||
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
@@ -584,7 +599,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
case BTF_KIND_DATASEC:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
d->type_states[id].order_state = ORDERED;
|
||||
return 0;
|
||||
|
||||
@@ -734,6 +749,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
btf_dump_emit_type(d, t->type, cont_id);
|
||||
break;
|
||||
case BTF_KIND_ARRAY:
|
||||
@@ -1154,6 +1170,7 @@ skip_mod:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
id = t->type;
|
||||
break;
|
||||
case BTF_KIND_ARRAY:
|
||||
@@ -1322,6 +1339,11 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
case BTF_KIND_RESTRICT:
|
||||
btf_dump_printf(d, " restrict");
|
||||
break;
|
||||
case BTF_KIND_TYPE_TAG:
|
||||
btf_dump_emit_mods(d, decls);
|
||||
name = btf_name_of(d, t->name_off);
|
||||
btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name);
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = btf_array(t);
|
||||
const struct btf_type *next_t;
|
||||
@@ -1562,29 +1584,28 @@ static int btf_dump_get_bitfield_value(struct btf_dump *d,
|
||||
__u64 *value)
|
||||
{
|
||||
__u16 left_shift_bits, right_shift_bits;
|
||||
__u8 nr_copy_bits, nr_copy_bytes;
|
||||
const __u8 *bytes = data;
|
||||
int sz = t->size;
|
||||
__u8 nr_copy_bits;
|
||||
__u64 num = 0;
|
||||
int i;
|
||||
|
||||
/* Maximum supported bitfield size is 64 bits */
|
||||
if (sz > 8) {
|
||||
pr_warn("unexpected bitfield size %d\n", sz);
|
||||
if (t->size > 8) {
|
||||
pr_warn("unexpected bitfield size %d\n", t->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Bitfield value retrieval is done in two steps; first relevant bytes are
|
||||
* stored in num, then we left/right shift num to eliminate irrelevant bits.
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
for (i = t->size - 1; i >= 0; i--)
|
||||
num = num * 256 + bytes[i];
|
||||
nr_copy_bits = bit_sz + bits_offset;
|
||||
nr_copy_bytes = t->size;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
for (i = nr_copy_bytes - 1; i >= 0; i--)
|
||||
num = num * 256 + bytes[i];
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
for (i = 0; i < nr_copy_bytes; i++)
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
for (i = 0; i < t->size; i++)
|
||||
num = num * 256 + bytes[i];
|
||||
nr_copy_bits = t->size * 8 - bits_offset;
|
||||
#else
|
||||
# error "Unrecognized __BYTE_ORDER__"
|
||||
#endif
|
||||
@@ -1658,9 +1679,15 @@ static int btf_dump_base_type_check_zero(struct btf_dump *d,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ptr_is_aligned(const void *data, int data_sz)
|
||||
static bool ptr_is_aligned(const struct btf *btf, __u32 type_id,
|
||||
const void *data)
|
||||
{
|
||||
return ((uintptr_t)data) % data_sz == 0;
|
||||
int alignment = btf__align_of(btf, type_id);
|
||||
|
||||
if (alignment == 0)
|
||||
return false;
|
||||
|
||||
return ((uintptr_t)data) % alignment == 0;
|
||||
}
|
||||
|
||||
static int btf_dump_int_data(struct btf_dump *d,
|
||||
@@ -1671,9 +1698,10 @@ static int btf_dump_int_data(struct btf_dump *d,
|
||||
{
|
||||
__u8 encoding = btf_int_encoding(t);
|
||||
bool sign = encoding & BTF_INT_SIGNED;
|
||||
char buf[16] __attribute__((aligned(16)));
|
||||
int sz = t->size;
|
||||
|
||||
if (sz == 0) {
|
||||
if (sz == 0 || sz > sizeof(buf)) {
|
||||
pr_warn("unexpected size %d for id [%u]\n", sz, type_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1681,8 +1709,10 @@ static int btf_dump_int_data(struct btf_dump *d,
|
||||
/* handle packed int data - accesses of integers not aligned on
|
||||
* int boundaries can cause problems on some platforms.
|
||||
*/
|
||||
if (!ptr_is_aligned(data, sz))
|
||||
return btf_dump_bitfield_data(d, t, data, 0, 0);
|
||||
if (!ptr_is_aligned(d->btf, type_id, data)) {
|
||||
memcpy(buf, data, sz);
|
||||
data = buf;
|
||||
}
|
||||
|
||||
switch (sz) {
|
||||
case 16: {
|
||||
@@ -1692,10 +1722,10 @@ static int btf_dump_int_data(struct btf_dump *d,
|
||||
/* avoid use of __int128 as some 32-bit platforms do not
|
||||
* support it.
|
||||
*/
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
lsi = ints[0];
|
||||
msi = ints[1];
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
lsi = ints[1];
|
||||
msi = ints[0];
|
||||
#else
|
||||
@@ -1768,7 +1798,7 @@ static int btf_dump_float_data(struct btf_dump *d,
|
||||
int sz = t->size;
|
||||
|
||||
/* handle unaligned data; copy to local union */
|
||||
if (!ptr_is_aligned(data, sz)) {
|
||||
if (!ptr_is_aligned(d->btf, type_id, data)) {
|
||||
memcpy(&fl, data, sz);
|
||||
flp = &fl;
|
||||
}
|
||||
@@ -1931,7 +1961,7 @@ static int btf_dump_ptr_data(struct btf_dump *d,
|
||||
__u32 id,
|
||||
const void *data)
|
||||
{
|
||||
if (ptr_is_aligned(data, d->ptr_sz) && d->ptr_sz == sizeof(void *)) {
|
||||
if (ptr_is_aligned(d->btf, id, data) && d->ptr_sz == sizeof(void *)) {
|
||||
btf_dump_type_values(d, "%p", *(void **)data);
|
||||
} else {
|
||||
union ptr_data pt;
|
||||
@@ -1951,10 +1981,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
|
||||
__u32 id,
|
||||
__s64 *value)
|
||||
{
|
||||
int sz = t->size;
|
||||
|
||||
/* handle unaligned enum value */
|
||||
if (!ptr_is_aligned(data, sz)) {
|
||||
if (!ptr_is_aligned(d->btf, id, data)) {
|
||||
__u64 val;
|
||||
int err;
|
||||
|
||||
@@ -2188,7 +2216,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
|
||||
__u8 bits_offset,
|
||||
__u8 bit_sz)
|
||||
{
|
||||
int size, err;
|
||||
int size, err = 0;
|
||||
|
||||
size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset);
|
||||
if (size < 0)
|
||||
@@ -2217,7 +2245,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
case BTF_KIND_TAG:
|
||||
case BTF_KIND_DECL_TAG:
|
||||
err = btf_dump_unsupported_data(d, t, id);
|
||||
break;
|
||||
case BTF_KIND_INT:
|
||||
|
||||
259
src/gen_loader.c
259
src/gen_loader.c
@@ -13,11 +13,12 @@
|
||||
#include "hashmap.h"
|
||||
#include "bpf_gen_internal.h"
|
||||
#include "skel_internal.h"
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define MAX_USED_MAPS 64
|
||||
#define MAX_USED_PROGS 32
|
||||
#define MAX_KFUNC_DESCS 256
|
||||
#define MAX_FD_ARRAY_SZ (MAX_USED_PROGS + MAX_KFUNC_DESCS)
|
||||
#define MAX_FD_ARRAY_SZ (MAX_USED_MAPS + MAX_KFUNC_DESCS)
|
||||
|
||||
/* The following structure describes the stack layout of the loader program.
|
||||
* In addition R6 contains the pointer to context.
|
||||
@@ -32,8 +33,8 @@
|
||||
*/
|
||||
struct loader_stack {
|
||||
__u32 btf_fd;
|
||||
__u32 prog_fd[MAX_USED_PROGS];
|
||||
__u32 inner_map_fd;
|
||||
__u32 prog_fd[MAX_USED_PROGS];
|
||||
};
|
||||
|
||||
#define stack_off(field) \
|
||||
@@ -41,6 +42,11 @@ struct loader_stack {
|
||||
|
||||
#define attr_field(attr, field) (attr + offsetof(union bpf_attr, field))
|
||||
|
||||
static int blob_fd_array_off(struct bpf_gen *gen, int index)
|
||||
{
|
||||
return gen->fd_array + index * sizeof(int);
|
||||
}
|
||||
|
||||
static int realloc_insn_buf(struct bpf_gen *gen, __u32 size)
|
||||
{
|
||||
size_t off = gen->insn_cur - gen->insn_start;
|
||||
@@ -101,11 +107,15 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in
|
||||
emit(gen, insn2);
|
||||
}
|
||||
|
||||
void bpf_gen__init(struct bpf_gen *gen, int log_level)
|
||||
static int add_data(struct bpf_gen *gen, const void *data, __u32 size);
|
||||
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
|
||||
|
||||
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
|
||||
{
|
||||
size_t stack_sz = sizeof(struct loader_stack);
|
||||
size_t stack_sz = sizeof(struct loader_stack), nr_progs_sz;
|
||||
int i;
|
||||
|
||||
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
|
||||
gen->log_level = log_level;
|
||||
/* save ctx pointer into R6 */
|
||||
emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
|
||||
@@ -117,19 +127,27 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level)
|
||||
emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
|
||||
emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
|
||||
|
||||
/* amount of stack actually used, only used to calculate iterations, not stack offset */
|
||||
nr_progs_sz = offsetof(struct loader_stack, prog_fd[nr_progs]);
|
||||
/* jump over cleanup code */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0,
|
||||
/* size of cleanup code below */
|
||||
(stack_sz / 4) * 3 + 2));
|
||||
/* size of cleanup code below (including map fd cleanup) */
|
||||
(nr_progs_sz / 4) * 3 + 2 +
|
||||
/* 6 insns for emit_sys_close_blob,
|
||||
* 6 insns for debug_regs in emit_sys_close_blob
|
||||
*/
|
||||
nr_maps * (6 + (gen->log_level ? 6 : 0))));
|
||||
|
||||
/* 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) {
|
||||
for (i = 0; i < nr_progs_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));
|
||||
}
|
||||
for (i = 0; i < nr_maps; i++)
|
||||
emit_sys_close_blob(gen, blob_fd_array_off(gen, i));
|
||||
/* 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());
|
||||
@@ -159,8 +177,6 @@ static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
|
||||
*/
|
||||
static int add_map_fd(struct bpf_gen *gen)
|
||||
{
|
||||
if (!gen->fd_array)
|
||||
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
|
||||
if (gen->nr_maps == MAX_USED_MAPS) {
|
||||
pr_warn("Total maps exceeds %d\n", MAX_USED_MAPS);
|
||||
gen->error = -E2BIG;
|
||||
@@ -173,8 +189,6 @@ static int add_kfunc_btf_fd(struct bpf_gen *gen)
|
||||
{
|
||||
int cur;
|
||||
|
||||
if (!gen->fd_array)
|
||||
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
|
||||
if (gen->nr_fd_array == MAX_KFUNC_DESCS) {
|
||||
cur = add_data(gen, NULL, sizeof(int));
|
||||
return (cur - gen->fd_array) / sizeof(int);
|
||||
@@ -182,11 +196,6 @@ static int add_kfunc_btf_fd(struct bpf_gen *gen)
|
||||
return MAX_USED_MAPS + gen->nr_fd_array++;
|
||||
}
|
||||
|
||||
static int blob_fd_array_off(struct bpf_gen *gen, int index)
|
||||
{
|
||||
return gen->fd_array + index * sizeof(int);
|
||||
}
|
||||
|
||||
static int insn_bytes_to_bpf_size(__u32 sz)
|
||||
{
|
||||
switch (sz) {
|
||||
@@ -358,10 +367,15 @@ static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
|
||||
__emit_sys_close(gen);
|
||||
}
|
||||
|
||||
int bpf_gen__finish(struct bpf_gen *gen)
|
||||
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nr_progs != gen->nr_progs || nr_maps != gen->nr_maps) {
|
||||
pr_warn("progs/maps mismatch\n");
|
||||
gen->error = -EFAULT;
|
||||
return gen->error;
|
||||
}
|
||||
emit_sys_close_stack(gen, stack_off(btf_fd));
|
||||
for (i = 0; i < gen->nr_progs; i++)
|
||||
move_stack2ctx(gen,
|
||||
@@ -431,46 +445,33 @@ void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
|
||||
}
|
||||
|
||||
void bpf_gen__map_create(struct bpf_gen *gen,
|
||||
struct bpf_create_map_attr *map_attr, int map_idx)
|
||||
enum bpf_map_type map_type,
|
||||
const char *map_name,
|
||||
__u32 key_size, __u32 value_size, __u32 max_entries,
|
||||
struct bpf_map_create_opts *map_attr, int map_idx)
|
||||
{
|
||||
int attr_size = offsetofend(union bpf_attr, btf_vmlinux_value_type_id);
|
||||
int attr_size = offsetofend(union bpf_attr, map_extra);
|
||||
bool close_inner_map_fd = false;
|
||||
int map_create_attr, idx;
|
||||
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_type = map_type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = 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.map_extra = map_attr->map_extra;
|
||||
if (map_name)
|
||||
memcpy(attr.map_name, map_name,
|
||||
min((unsigned)strlen(map_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;
|
||||
}
|
||||
attr.max_entries = max_entries;
|
||||
attr.btf_key_type_id = map_attr->btf_key_type_id;
|
||||
attr.btf_value_type_id = map_attr->btf_value_type_id;
|
||||
|
||||
pr_debug("gen: map_create: %s idx %d type %d value_type_id %d\n",
|
||||
attr.map_name, map_idx, map_attr->map_type, attr.btf_value_type_id);
|
||||
attr.map_name, map_idx, map_type, attr.btf_value_type_id);
|
||||
|
||||
map_create_attr = add_data(gen, &attr, attr_size);
|
||||
if (attr.btf_value_type_id)
|
||||
@@ -497,7 +498,7 @@ void bpf_gen__map_create(struct bpf_gen *gen,
|
||||
/* emit MAP_CREATE command */
|
||||
emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size);
|
||||
debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d",
|
||||
attr.map_name, map_idx, map_attr->map_type, attr.value_size,
|
||||
attr.map_name, map_idx, map_type, value_size,
|
||||
attr.btf_value_type_id);
|
||||
emit_check_err(gen);
|
||||
/* remember map_fd in the stack, if successful */
|
||||
@@ -559,7 +560,7 @@ static void emit_find_attach_target(struct bpf_gen *gen)
|
||||
}
|
||||
|
||||
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
int kind, int insn_idx)
|
||||
bool is_typeless, int kind, int insn_idx)
|
||||
{
|
||||
struct ksym_relo_desc *relo;
|
||||
|
||||
@@ -572,6 +573,7 @@ void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
relo += gen->relo_cnt;
|
||||
relo->name = name;
|
||||
relo->is_weak = is_weak;
|
||||
relo->is_typeless = is_typeless;
|
||||
relo->kind = kind;
|
||||
relo->insn_idx = insn_idx;
|
||||
gen->relo_cnt++;
|
||||
@@ -581,8 +583,9 @@ void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, bool is_weak,
|
||||
static struct ksym_desc *get_ksym_desc(struct bpf_gen *gen, struct ksym_relo_desc *relo)
|
||||
{
|
||||
struct ksym_desc *kdesc;
|
||||
int i;
|
||||
|
||||
for (int i = 0; i < gen->nr_ksyms; i++) {
|
||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||
if (!strcmp(gen->ksyms[i].name, relo->name)) {
|
||||
gen->ksyms[i].ref++;
|
||||
return &gen->ksyms[i];
|
||||
@@ -621,6 +624,29 @@ static void emit_bpf_find_by_name_kind(struct bpf_gen *gen, struct ksym_relo_des
|
||||
debug_ret(gen, "find_by_name_kind(%s,%d)", relo->name, relo->kind);
|
||||
}
|
||||
|
||||
/* Overwrites BPF_REG_{0, 1, 2, 3, 4, 7}
|
||||
* Returns result in BPF_REG_7
|
||||
* Returns u64 symbol addr in BPF_REG_9
|
||||
*/
|
||||
static void emit_bpf_kallsyms_lookup_name(struct bpf_gen *gen, struct ksym_relo_desc *relo)
|
||||
{
|
||||
int name_off, len = strlen(relo->name) + 1, res_off;
|
||||
|
||||
name_off = add_data(gen, relo->name, len);
|
||||
res_off = add_data(gen, NULL, 8); /* res is u64 */
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||
0, 0, 0, name_off));
|
||||
emit(gen, BPF_MOV64_IMM(BPF_REG_2, len));
|
||||
emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_4, BPF_PSEUDO_MAP_IDX_VALUE,
|
||||
0, 0, 0, res_off));
|
||||
emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_4));
|
||||
emit(gen, BPF_EMIT_CALL(BPF_FUNC_kallsyms_lookup_name));
|
||||
emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_7, 0));
|
||||
emit(gen, BPF_MOV64_REG(BPF_REG_7, BPF_REG_0));
|
||||
debug_ret(gen, "kallsyms_lookup_name(%s,%d)", relo->name, relo->kind);
|
||||
}
|
||||
|
||||
/* Expects:
|
||||
* BPF_REG_8 - pointer to instruction
|
||||
*
|
||||
@@ -700,10 +726,27 @@ log:
|
||||
relo->name, kdesc->ref);
|
||||
}
|
||||
|
||||
static void emit_ksym_relo_log(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
||||
int ref)
|
||||
{
|
||||
if (!gen->log_level)
|
||||
return;
|
||||
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_8,
|
||||
offsetof(struct bpf_insn, imm)));
|
||||
emit(gen, BPF_LDX_MEM(BPF_H, BPF_REG_9, BPF_REG_8, sizeof(struct bpf_insn) +
|
||||
offsetof(struct bpf_insn, imm)));
|
||||
debug_regs(gen, BPF_REG_7, BPF_REG_9, " var t=%d w=%d (%s:count=%d): imm[0]: %%d, imm[1]: %%d",
|
||||
relo->is_typeless, relo->is_weak, relo->name, ref);
|
||||
emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code)));
|
||||
debug_regs(gen, BPF_REG_9, -1, " var t=%d w=%d (%s:count=%d): insn.reg",
|
||||
relo->is_typeless, relo->is_weak, relo->name, ref);
|
||||
}
|
||||
|
||||
/* Expects:
|
||||
* BPF_REG_8 - pointer to instruction
|
||||
*/
|
||||
static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn)
|
||||
static void emit_relo_ksym_typeless(struct bpf_gen *gen,
|
||||
struct ksym_relo_desc *relo, int insn)
|
||||
{
|
||||
struct ksym_desc *kdesc;
|
||||
|
||||
@@ -718,25 +761,81 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo,
|
||||
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
||||
goto log;
|
||||
}
|
||||
/* remember insn offset, so we can copy ksym addr later */
|
||||
kdesc->insn = insn;
|
||||
/* skip typeless ksym_desc in fd closing loop in cleanup_relos */
|
||||
kdesc->typeless = true;
|
||||
emit_bpf_kallsyms_lookup_name(gen, relo);
|
||||
emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, -ENOENT, 1));
|
||||
emit_check_err(gen);
|
||||
/* store lower half of addr into insn[insn_idx].imm */
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9, offsetof(struct bpf_insn, imm)));
|
||||
/* store upper half of addr into insn[insn_idx + 1].imm */
|
||||
emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32));
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9,
|
||||
sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
|
||||
log:
|
||||
emit_ksym_relo_log(gen, relo, kdesc->ref);
|
||||
}
|
||||
|
||||
static __u32 src_reg_mask(void)
|
||||
{
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
return 0x0f; /* src_reg,dst_reg,... */
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
return 0xf0; /* dst_reg,src_reg,... */
|
||||
#else
|
||||
#error "Unsupported bit endianness, cannot proceed"
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Expects:
|
||||
* BPF_REG_8 - pointer to instruction
|
||||
*/
|
||||
static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn)
|
||||
{
|
||||
struct ksym_desc *kdesc;
|
||||
__u32 reg_mask;
|
||||
|
||||
kdesc = get_ksym_desc(gen, relo);
|
||||
if (!kdesc)
|
||||
return;
|
||||
/* try to copy from existing ldimm64 insn */
|
||||
if (kdesc->ref > 1) {
|
||||
move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4,
|
||||
kdesc->insn + offsetof(struct bpf_insn, imm));
|
||||
move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4,
|
||||
kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
|
||||
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_9, BPF_REG_8, offsetof(struct bpf_insn, imm)));
|
||||
/* jump over src_reg adjustment if imm is not 0 */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 3));
|
||||
goto clear_src_reg;
|
||||
}
|
||||
/* remember insn offset, so we can copy BTF ID and FD later */
|
||||
kdesc->insn = insn;
|
||||
emit_bpf_find_by_name_kind(gen, relo);
|
||||
emit_check_err(gen);
|
||||
if (!relo->is_weak)
|
||||
emit_check_err(gen);
|
||||
/* set default values as 0 */
|
||||
emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, offsetof(struct bpf_insn, imm), 0));
|
||||
emit(gen, BPF_ST_MEM(BPF_W, BPF_REG_8, sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 0));
|
||||
/* skip success case stores if ret < 0 */
|
||||
emit(gen, BPF_JMP_IMM(BPF_JSLT, BPF_REG_7, 0, 4));
|
||||
/* store btf_id into insn[insn_idx].imm */
|
||||
emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_7, offsetof(struct bpf_insn, imm)));
|
||||
/* 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_8, BPF_REG_7,
|
||||
sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
|
||||
log:
|
||||
if (!gen->log_level)
|
||||
return;
|
||||
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_8,
|
||||
offsetof(struct bpf_insn, imm)));
|
||||
emit(gen, BPF_LDX_MEM(BPF_H, BPF_REG_9, BPF_REG_8, sizeof(struct bpf_insn) +
|
||||
offsetof(struct bpf_insn, imm)));
|
||||
debug_regs(gen, BPF_REG_7, BPF_REG_9, " var (%s:count=%d): imm: %%d, fd: %%d",
|
||||
relo->name, kdesc->ref);
|
||||
emit(gen, BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0, 3));
|
||||
clear_src_reg:
|
||||
/* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */
|
||||
reg_mask = src_reg_mask();
|
||||
emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code)));
|
||||
emit(gen, BPF_ALU32_IMM(BPF_AND, BPF_REG_9, reg_mask));
|
||||
emit(gen, BPF_STX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, offsetofend(struct bpf_insn, code)));
|
||||
|
||||
emit_ksym_relo_log(gen, relo, kdesc->ref);
|
||||
}
|
||||
|
||||
static void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insns)
|
||||
@@ -748,7 +847,10 @@ static void emit_relo(struct bpf_gen *gen, struct ksym_relo_desc *relo, int insn
|
||||
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_8, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, insn));
|
||||
switch (relo->kind) {
|
||||
case BTF_KIND_VAR:
|
||||
emit_relo_ksym_btf(gen, relo, insn);
|
||||
if (relo->is_typeless)
|
||||
emit_relo_ksym_typeless(gen, relo, insn);
|
||||
else
|
||||
emit_relo_ksym_btf(gen, relo, insn);
|
||||
break;
|
||||
case BTF_KIND_FUNC:
|
||||
emit_relo_kfunc_btf(gen, relo, insn);
|
||||
@@ -773,12 +875,13 @@ static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||
int i, insn;
|
||||
|
||||
for (i = 0; i < gen->nr_ksyms; i++) {
|
||||
if (gen->ksyms[i].kind == BTF_KIND_VAR) {
|
||||
/* only close fds for typed ksyms and kfuncs */
|
||||
if (gen->ksyms[i].kind == BTF_KIND_VAR && !gen->ksyms[i].typeless) {
|
||||
/* close fd recorded in insn[insn_idx + 1].imm */
|
||||
insn = gen->ksyms[i].insn;
|
||||
insn += sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm);
|
||||
emit_sys_close_blob(gen, insn);
|
||||
} else { /* BTF_KIND_FUNC */
|
||||
} else if (gen->ksyms[i].kind == BTF_KIND_FUNC) {
|
||||
emit_sys_close_blob(gen, blob_fd_array_off(gen, gen->ksyms[i].off));
|
||||
if (gen->ksyms[i].off < MAX_FD_ARRAY_SZ)
|
||||
gen->nr_fd_array--;
|
||||
@@ -797,27 +900,27 @@ static void cleanup_relos(struct bpf_gen *gen, int insns)
|
||||
}
|
||||
|
||||
void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||
struct bpf_prog_load_params *load_attr, int prog_idx)
|
||||
enum bpf_prog_type prog_type, const char *prog_name,
|
||||
const char *license, struct bpf_insn *insns, size_t insn_cnt,
|
||||
struct bpf_prog_load_opts *load_attr, int prog_idx)
|
||||
{
|
||||
int attr_size = offsetofend(union bpf_attr, fd_array);
|
||||
int prog_load_attr, license, insns, func_info, line_info;
|
||||
int prog_load_attr, license_off, insns_off, 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);
|
||||
pr_debug("gen: prog_load: type %d insns_cnt %zd\n", prog_type, insn_cnt);
|
||||
/* add license string to blob of bytes */
|
||||
license = add_data(gen, load_attr->license, strlen(load_attr->license) + 1);
|
||||
license_off = add_data(gen, license, strlen(license) + 1);
|
||||
/* add insns to blob of bytes */
|
||||
insns = add_data(gen, load_attr->insns,
|
||||
load_attr->insn_cnt * sizeof(struct bpf_insn));
|
||||
insns_off = add_data(gen, insns, insn_cnt * sizeof(struct bpf_insn));
|
||||
|
||||
attr.prog_type = load_attr->prog_type;
|
||||
attr.prog_type = prog_type;
|
||||
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||
attr.kern_version = 0;
|
||||
attr.insn_cnt = (__u32)load_attr->insn_cnt;
|
||||
attr.insn_cnt = (__u32)insn_cnt;
|
||||
attr.prog_flags = load_attr->prog_flags;
|
||||
|
||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
@@ -830,15 +933,15 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||
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));
|
||||
memcpy(attr.prog_name, prog_name,
|
||||
min((unsigned)strlen(prog_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);
|
||||
emit_rel_store(gen, attr_field(prog_load_attr, license), license_off);
|
||||
|
||||
/* populate union bpf_attr with a pointer to instructions */
|
||||
emit_rel_store(gen, attr_field(prog_load_attr, insns), insns);
|
||||
emit_rel_store(gen, attr_field(prog_load_attr, insns), insns_off);
|
||||
|
||||
/* populate union bpf_attr with a pointer to func_info */
|
||||
emit_rel_store(gen, attr_field(prog_load_attr, func_info), func_info);
|
||||
@@ -870,12 +973,12 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
|
||||
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_relos(gen, insns_off);
|
||||
/* 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);
|
||||
cleanup_relos(gen, insns_off);
|
||||
if (gen->attach_kind)
|
||||
emit_sys_close_blob(gen,
|
||||
attr_field(prog_load_attr, attach_btf_obj_fd));
|
||||
|
||||
1715
src/libbpf.c
1715
src/libbpf.c
File diff suppressed because it is too large
Load Diff
153
src/libbpf.h
153
src/libbpf.h
@@ -24,6 +24,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBBPF_API __u32 libbpf_major_version(void);
|
||||
LIBBPF_API __u32 libbpf_minor_version(void);
|
||||
LIBBPF_API const char *libbpf_version_string(void);
|
||||
|
||||
enum libbpf_errno {
|
||||
__LIBBPF_ERRNO__START = 4000,
|
||||
|
||||
@@ -168,7 +172,8 @@ LIBBPF_API struct bpf_program *
|
||||
bpf_object__find_program_by_name(const struct bpf_object *obj,
|
||||
const char *name);
|
||||
|
||||
LIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "track bpf_objects in application code instead")
|
||||
struct bpf_object *bpf_object__next(struct bpf_object *prev);
|
||||
#define bpf_object__for_each_safe(pos, tmp) \
|
||||
for ((pos) = bpf_object__next(NULL), \
|
||||
(tmp) = bpf_object__next(pos); \
|
||||
@@ -224,14 +229,51 @@ LIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);
|
||||
|
||||
/* returns program size in bytes */
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insn_cnt() instead")
|
||||
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);
|
||||
|
||||
LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
|
||||
__u32 kern_version);
|
||||
struct bpf_insn;
|
||||
|
||||
/**
|
||||
* @brief **bpf_program__insns()** gives read-only access to BPF program's
|
||||
* underlying BPF instructions.
|
||||
* @param prog BPF program for which to return instructions
|
||||
* @return a pointer to an array of BPF instructions that belong to the
|
||||
* specified BPF program
|
||||
*
|
||||
* Returned pointer is always valid and not NULL. Number of `struct bpf_insn`
|
||||
* pointed to can be fetched using **bpf_program__insn_cnt()** API.
|
||||
*
|
||||
* Keep in mind, libbpf can modify and append/delete BPF program's
|
||||
* instructions as it processes BPF object file and prepares everything for
|
||||
* uploading into the kernel. So depending on the point in BPF object
|
||||
* lifetime, **bpf_program__insns()** can return different sets of
|
||||
* instructions. As an example, during BPF object load phase BPF program
|
||||
* instructions will be CO-RE-relocated, BPF subprograms instructions will be
|
||||
* appended, ldimm64 instructions will have FDs embedded, etc. So instructions
|
||||
* returned before **bpf_object__load()** and after it might be quite
|
||||
* different.
|
||||
*/
|
||||
LIBBPF_API const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog);
|
||||
/**
|
||||
* @brief **bpf_program__insn_cnt()** returns number of `struct bpf_insn`'s
|
||||
* that form specified BPF program.
|
||||
* @param prog BPF program for which to return number of BPF instructions
|
||||
*
|
||||
* See **bpf_program__insns()** documentation for notes on how libbpf can
|
||||
* change instructions and their count during different phases of
|
||||
* **bpf_object** lifetime.
|
||||
*/
|
||||
LIBBPF_API size_t bpf_program__insn_cnt(const struct bpf_program *prog);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use bpf_object__load() instead")
|
||||
LIBBPF_API int bpf_program__load(struct bpf_program *prog, const char *license, __u32 kern_version);
|
||||
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
|
||||
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
|
||||
LIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
@@ -365,8 +407,6 @@ LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_iter(const struct bpf_program *prog,
|
||||
const struct bpf_iter_attach_opts *opts);
|
||||
|
||||
struct bpf_insn;
|
||||
|
||||
/*
|
||||
* Libbpf allows callers to adjust BPF programs before being loaded
|
||||
* into kernel. One program in an object file can be transformed into
|
||||
@@ -395,7 +435,6 @@ struct bpf_insn;
|
||||
* one instance. In this case bpf_program__fd(prog) is equal to
|
||||
* bpf_program__nth_fd(prog, 0).
|
||||
*/
|
||||
|
||||
struct bpf_prog_prep_result {
|
||||
/*
|
||||
* If not NULL, load new instruction array.
|
||||
@@ -424,9 +463,11 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
|
||||
struct bpf_insn *insns, int insns_cnt,
|
||||
struct bpf_prog_prep_result *res);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insns() for getting bpf_program instructions")
|
||||
LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
|
||||
bpf_program_prep_t prep);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
|
||||
LIBBPF_API int bpf_program__nth_fd(const struct bpf_program *prog, int n);
|
||||
|
||||
/*
|
||||
@@ -456,6 +497,9 @@ LIBBPF_API void
|
||||
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
LIBBPF_API __u32 bpf_program__flags(const struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_flags(struct bpf_program *prog, __u32 flags);
|
||||
|
||||
LIBBPF_API int
|
||||
bpf_program__set_attach_target(struct bpf_program *prog, int attach_prog_fd,
|
||||
const char *attach_func_name);
|
||||
@@ -562,6 +606,9 @@ LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
|
||||
/* get/set map if_index */
|
||||
LIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
||||
/* get/set map map_extra flags */
|
||||
LIBBPF_API __u64 bpf_map__map_extra(const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_map__set_map_extra(struct bpf_map *map, __u64 map_extra);
|
||||
|
||||
typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
|
||||
LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
||||
@@ -635,8 +682,9 @@ struct bpf_prog_load_attr {
|
||||
|
||||
LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
||||
struct bpf_object **pobj, int *prog_fd);
|
||||
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
||||
struct bpf_object **pobj, int *prog_fd);
|
||||
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_object__open() and bpf_object__load() instead")
|
||||
LIBBPF_API int bpf_prog_load_deprecated(const char *file, enum bpf_prog_type type,
|
||||
struct bpf_object **pobj, int *prog_fd);
|
||||
|
||||
/* XDP related API */
|
||||
struct xdp_link_info {
|
||||
@@ -734,18 +782,52 @@ typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
|
||||
|
||||
/* common use perf buffer options */
|
||||
struct perf_buffer_opts {
|
||||
/* if specified, sample_cb is called for each sample */
|
||||
perf_buffer_sample_fn sample_cb;
|
||||
/* if specified, lost_cb is called for each batch of lost samples */
|
||||
perf_buffer_lost_fn lost_cb;
|
||||
/* ctx is provided to sample_cb and lost_cb */
|
||||
void *ctx;
|
||||
union {
|
||||
size_t sz;
|
||||
struct { /* DEPRECATED: will be removed in v1.0 */
|
||||
/* if specified, sample_cb is called for each sample */
|
||||
perf_buffer_sample_fn sample_cb;
|
||||
/* if specified, lost_cb is called for each batch of lost samples */
|
||||
perf_buffer_lost_fn lost_cb;
|
||||
/* ctx is provided to sample_cb and lost_cb */
|
||||
void *ctx;
|
||||
};
|
||||
};
|
||||
};
|
||||
#define perf_buffer_opts__last_field sz
|
||||
|
||||
/**
|
||||
* @brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
|
||||
* BPF_PERF_EVENT_ARRAY map
|
||||
* @param map_fd FD of BPF_PERF_EVENT_ARRAY BPF map that will be used by BPF
|
||||
* code to send data over to user-space
|
||||
* @param page_cnt number of memory pages allocated for each per-CPU buffer
|
||||
* @param sample_cb function called on each received data record
|
||||
* @param lost_cb function called when record loss has occurred
|
||||
* @param ctx user-provided extra context passed into *sample_cb* and *lost_cb*
|
||||
* @return a new instance of struct perf_buffer on success, NULL on error with
|
||||
* *errno* containing an error code
|
||||
*/
|
||||
LIBBPF_API struct perf_buffer *
|
||||
perf_buffer__new(int map_fd, size_t page_cnt,
|
||||
perf_buffer_sample_fn sample_cb, perf_buffer_lost_fn lost_cb, void *ctx,
|
||||
const struct perf_buffer_opts *opts);
|
||||
|
||||
LIBBPF_API struct perf_buffer *
|
||||
perf_buffer__new_v0_6_0(int map_fd, size_t page_cnt,
|
||||
perf_buffer_sample_fn sample_cb, perf_buffer_lost_fn lost_cb, void *ctx,
|
||||
const struct perf_buffer_opts *opts);
|
||||
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "use new variant of perf_buffer__new() instead")
|
||||
struct perf_buffer *perf_buffer__new_deprecated(int map_fd, size_t page_cnt,
|
||||
const struct perf_buffer_opts *opts);
|
||||
|
||||
#define perf_buffer__new(...) ___libbpf_overload(___perf_buffer_new, __VA_ARGS__)
|
||||
#define ___perf_buffer_new6(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts) \
|
||||
perf_buffer__new(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts)
|
||||
#define ___perf_buffer_new3(map_fd, page_cnt, opts) \
|
||||
perf_buffer__new_deprecated(map_fd, page_cnt, opts)
|
||||
|
||||
enum bpf_perf_event_ret {
|
||||
LIBBPF_PERF_EVENT_DONE = 0,
|
||||
LIBBPF_PERF_EVENT_ERROR = -1,
|
||||
@@ -759,12 +841,21 @@ typedef enum bpf_perf_event_ret
|
||||
|
||||
/* raw perf buffer options, giving most power and control */
|
||||
struct perf_buffer_raw_opts {
|
||||
/* perf event attrs passed directly into perf_event_open() */
|
||||
struct perf_event_attr *attr;
|
||||
/* raw event callback */
|
||||
perf_buffer_event_fn event_cb;
|
||||
/* ctx is provided to event_cb */
|
||||
void *ctx;
|
||||
union {
|
||||
struct {
|
||||
size_t sz;
|
||||
long :0;
|
||||
long :0;
|
||||
};
|
||||
struct { /* DEPRECATED: will be removed in v1.0 */
|
||||
/* perf event attrs passed directly into perf_event_open() */
|
||||
struct perf_event_attr *attr;
|
||||
/* raw event callback */
|
||||
perf_buffer_event_fn event_cb;
|
||||
/* ctx is provided to event_cb */
|
||||
void *ctx;
|
||||
};
|
||||
};
|
||||
/* if cpu_cnt == 0, open all on all possible CPUs (up to the number of
|
||||
* max_entries of given PERF_EVENT_ARRAY map)
|
||||
*/
|
||||
@@ -774,11 +865,28 @@ struct perf_buffer_raw_opts {
|
||||
/* if cpu_cnt > 0, map_keys specify map keys to set per-CPU FDs for */
|
||||
int *map_keys;
|
||||
};
|
||||
#define perf_buffer_raw_opts__last_field map_keys
|
||||
|
||||
LIBBPF_API struct perf_buffer *
|
||||
perf_buffer__new_raw(int map_fd, size_t page_cnt,
|
||||
perf_buffer__new_raw(int map_fd, size_t page_cnt, struct perf_event_attr *attr,
|
||||
perf_buffer_event_fn event_cb, void *ctx,
|
||||
const struct perf_buffer_raw_opts *opts);
|
||||
|
||||
LIBBPF_API struct perf_buffer *
|
||||
perf_buffer__new_raw_v0_6_0(int map_fd, size_t page_cnt, struct perf_event_attr *attr,
|
||||
perf_buffer_event_fn event_cb, void *ctx,
|
||||
const struct perf_buffer_raw_opts *opts);
|
||||
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "use new variant of perf_buffer__new_raw() instead")
|
||||
struct perf_buffer *perf_buffer__new_raw_deprecated(int map_fd, size_t page_cnt,
|
||||
const struct perf_buffer_raw_opts *opts);
|
||||
|
||||
#define perf_buffer__new_raw(...) ___libbpf_overload(___perf_buffer_new_raw, __VA_ARGS__)
|
||||
#define ___perf_buffer_new_raw6(map_fd, page_cnt, attr, event_cb, ctx, opts) \
|
||||
perf_buffer__new_raw(map_fd, page_cnt, attr, event_cb, ctx, opts)
|
||||
#define ___perf_buffer_new_raw3(map_fd, page_cnt, opts) \
|
||||
perf_buffer__new_raw_deprecated(map_fd, page_cnt, opts)
|
||||
|
||||
LIBBPF_API void perf_buffer__free(struct perf_buffer *pb);
|
||||
LIBBPF_API int perf_buffer__epoll_fd(const struct perf_buffer *pb);
|
||||
LIBBPF_API int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms);
|
||||
@@ -877,12 +985,15 @@ struct bpf_prog_info_linear {
|
||||
__u8 data[];
|
||||
};
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use a custom linear prog_info wrapper")
|
||||
LIBBPF_API struct bpf_prog_info_linear *
|
||||
bpf_program__get_prog_info_linear(int fd, __u64 arrays);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use a custom linear prog_info wrapper")
|
||||
LIBBPF_API void
|
||||
bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
|
||||
|
||||
LIBBPF_DEPRECATED_SINCE(0, 6, "use a custom linear prog_info wrapper")
|
||||
LIBBPF_API void
|
||||
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
|
||||
|
||||
|
||||
@@ -389,10 +389,33 @@ LIBBPF_0.5.0 {
|
||||
|
||||
LIBBPF_0.6.0 {
|
||||
global:
|
||||
bpf_map__map_extra;
|
||||
bpf_map__set_map_extra;
|
||||
bpf_map_create;
|
||||
bpf_object__next_map;
|
||||
bpf_object__next_program;
|
||||
bpf_object__prev_map;
|
||||
bpf_object__prev_program;
|
||||
bpf_prog_load_deprecated;
|
||||
bpf_prog_load;
|
||||
bpf_program__flags;
|
||||
bpf_program__insn_cnt;
|
||||
bpf_program__insns;
|
||||
bpf_program__set_flags;
|
||||
btf__add_btf;
|
||||
btf__add_tag;
|
||||
btf__add_decl_tag;
|
||||
btf__add_type_tag;
|
||||
btf__dedup;
|
||||
btf__dedup_deprecated;
|
||||
btf__raw_data;
|
||||
btf__type_cnt;
|
||||
btf_dump__new;
|
||||
btf_dump__new_deprecated;
|
||||
libbpf_major_version;
|
||||
libbpf_minor_version;
|
||||
libbpf_version_string;
|
||||
perf_buffer__new;
|
||||
perf_buffer__new_deprecated;
|
||||
perf_buffer__new_raw;
|
||||
perf_buffer__new_raw_deprecated;
|
||||
} LIBBPF_0.5.0;
|
||||
|
||||
@@ -41,6 +41,18 @@
|
||||
#define __LIBBPF_MARK_DEPRECATED_0_7(X)
|
||||
#endif
|
||||
|
||||
/* This set of internal macros allows to do "function overloading" based on
|
||||
* number of arguments provided by used in backwards-compatible way during the
|
||||
* transition to libbpf 1.0
|
||||
* It's ugly but necessary evil that will be cleaned up when we get to 1.0.
|
||||
* See bpf_prog_load() overload for example.
|
||||
*/
|
||||
#define ___libbpf_cat(A, B) A ## B
|
||||
#define ___libbpf_select(NAME, NUM) ___libbpf_cat(NAME, NUM)
|
||||
#define ___libbpf_nth(_1, _2, _3, _4, _5, _6, N, ...) N
|
||||
#define ___libbpf_cnt(...) ___libbpf_nth(__VA_ARGS__, 6, 5, 4, 3, 2, 1)
|
||||
#define ___libbpf_overload(NAME, ...) ___libbpf_select(NAME, ___libbpf_cnt(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
/* Helper macro to declare and initialize libbpf options struct
|
||||
*
|
||||
* This dance with uninitialized declaration, followed by memset to zero,
|
||||
@@ -54,7 +66,7 @@
|
||||
* including any extra padding, it with memset() and then assigns initial
|
||||
* values provided by users in struct initializer-syntax as varargs.
|
||||
*/
|
||||
#define DECLARE_LIBBPF_OPTS(TYPE, NAME, ...) \
|
||||
#define LIBBPF_OPTS(TYPE, NAME, ...) \
|
||||
struct TYPE NAME = ({ \
|
||||
memset(&NAME, 0, sizeof(struct TYPE)); \
|
||||
(struct TYPE) { \
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "libbpf_legacy.h"
|
||||
#include "relo_core.h"
|
||||
|
||||
@@ -52,8 +54,8 @@
|
||||
#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)
|
||||
#ifndef ELF64_ST_VISIBILITY
|
||||
#define ELF64_ST_VISIBILITY(o) ((o) & 0x03)
|
||||
#endif
|
||||
|
||||
#define BTF_INFO_ENC(kind, kind_flag, vlen) \
|
||||
@@ -69,8 +71,10 @@
|
||||
#define BTF_VAR_SECINFO_ENC(type, offset, size) (type), (offset), (size)
|
||||
#define BTF_TYPE_FLOAT_ENC(name, sz) \
|
||||
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_FLOAT, 0, 0), sz)
|
||||
#define BTF_TYPE_TAG_ENC(value, type, component_idx) \
|
||||
BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TAG, 0, 0), type), (component_idx)
|
||||
#define BTF_TYPE_DECL_TAG_ENC(value, type, component_idx) \
|
||||
BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_DECL_TAG, 0, 0), type), (component_idx)
|
||||
#define BTF_TYPE_TYPE_TAG_ENC(value, type) \
|
||||
BTF_TYPE_ENC(value, BTF_INFO_ENC(BTF_KIND_TYPE_TAG, 0, 0), type)
|
||||
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
@@ -193,8 +197,9 @@ enum map_def_parts {
|
||||
MAP_DEF_NUMA_NODE = 0x080,
|
||||
MAP_DEF_PINNING = 0x100,
|
||||
MAP_DEF_INNER_MAP = 0x200,
|
||||
MAP_DEF_MAP_EXTRA = 0x400,
|
||||
|
||||
MAP_DEF_ALL = 0x3ff, /* combination of all above */
|
||||
MAP_DEF_ALL = 0x7ff, /* combination of all above */
|
||||
};
|
||||
|
||||
struct btf_map_def {
|
||||
@@ -208,6 +213,7 @@ struct btf_map_def {
|
||||
__u32 map_flags;
|
||||
__u32 numa_node;
|
||||
__u32 pinning;
|
||||
__u64 map_extra;
|
||||
};
|
||||
|
||||
int parse_btf_map_def(const char *map_name, struct btf *btf,
|
||||
@@ -272,41 +278,6 @@ int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz);
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len);
|
||||
|
||||
struct bpf_prog_load_params {
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
const char *name;
|
||||
const struct bpf_insn *insns;
|
||||
size_t insn_cnt;
|
||||
const char *license;
|
||||
__u32 kern_version;
|
||||
__u32 attach_prog_fd;
|
||||
__u32 attach_btf_obj_fd;
|
||||
__u32 attach_btf_id;
|
||||
__u32 prog_ifindex;
|
||||
__u32 prog_btf_fd;
|
||||
__u32 prog_flags;
|
||||
|
||||
__u32 func_info_rec_size;
|
||||
const void *func_info;
|
||||
__u32 func_info_cnt;
|
||||
|
||||
__u32 line_info_rec_size;
|
||||
const void *line_info;
|
||||
__u32 line_info_cnt;
|
||||
|
||||
__u32 log_level;
|
||||
char *log_buf;
|
||||
size_t log_buf_sz;
|
||||
int *fd_array;
|
||||
};
|
||||
|
||||
int libbpf__bpf_prog_load(const struct bpf_prog_load_params *load_attr);
|
||||
|
||||
int bpf_object__section_size(const struct bpf_object *obj, const char *name,
|
||||
__u32 *size);
|
||||
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
|
||||
__u32 *off);
|
||||
struct 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);
|
||||
@@ -472,4 +443,26 @@ static inline bool is_ldimm64_insn(struct bpf_insn *insn)
|
||||
return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
||||
}
|
||||
|
||||
/* if fd is stdin, stdout, or stderr, dup to a fd greater than 2
|
||||
* Takes ownership of the fd passed in, and closes it if calling
|
||||
* fcntl(fd, F_DUPFD_CLOEXEC, 3).
|
||||
*/
|
||||
static inline int ensure_good_fd(int fd)
|
||||
{
|
||||
int old_fd = fd, saved_errno;
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
if (fd < 3) {
|
||||
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
saved_errno = errno;
|
||||
close(old_fd);
|
||||
if (fd < 0) {
|
||||
pr_warn("failed to dup FD %d to FD > 2: %d\n", old_fd, -saved_errno);
|
||||
errno = saved_errno;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||
|
||||
@@ -52,14 +52,24 @@ enum libbpf_strict_mode {
|
||||
* allowed, with LIBBPF_STRICT_SEC_PREFIX this will become
|
||||
* unrecognized by libbpf and would have to be just SEC("xdp") and
|
||||
* SEC("xdp") and SEC("perf_event").
|
||||
*
|
||||
* Note, in this mode the program pin path will be based on the
|
||||
* function name instead of section name.
|
||||
*/
|
||||
LIBBPF_STRICT_SEC_NAME = 0x04,
|
||||
/*
|
||||
* Disable the global 'bpf_objects_list'. Maintaining this list adds
|
||||
* a race condition to bpf_object__open() and bpf_object__close().
|
||||
* Clients can maintain it on their own if it is valuable for them.
|
||||
*/
|
||||
LIBBPF_STRICT_NO_OBJECT_LIST = 0x08,
|
||||
|
||||
__LIBBPF_STRICT_LAST,
|
||||
};
|
||||
|
||||
LIBBPF_API int libbpf_set_strict_mode(enum libbpf_strict_mode mode);
|
||||
|
||||
#define DECLARE_LIBBPF_OPTS LIBBPF_OPTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -33,7 +33,7 @@ static int get_vendor_id(int ifindex)
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
@@ -68,21 +68,21 @@ static void
|
||||
probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
||||
size_t insns_cnt, char *buf, size_t buf_len, __u32 ifindex)
|
||||
{
|
||||
struct bpf_load_program_attr xattr = {};
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts);
|
||||
int fd;
|
||||
|
||||
switch (prog_type) {
|
||||
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
|
||||
xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
||||
opts.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
|
||||
break;
|
||||
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
|
||||
xattr.expected_attach_type = BPF_CGROUP_GETSOCKOPT;
|
||||
opts.expected_attach_type = BPF_CGROUP_GETSOCKOPT;
|
||||
break;
|
||||
case BPF_PROG_TYPE_SK_LOOKUP:
|
||||
xattr.expected_attach_type = BPF_SK_LOOKUP;
|
||||
opts.expected_attach_type = BPF_SK_LOOKUP;
|
||||
break;
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
xattr.kern_version = get_kernel_version();
|
||||
opts.kern_version = get_kernel_version();
|
||||
break;
|
||||
case BPF_PROG_TYPE_UNSPEC:
|
||||
case BPF_PROG_TYPE_SOCKET_FILTER:
|
||||
@@ -115,13 +115,11 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
||||
break;
|
||||
}
|
||||
|
||||
xattr.prog_type = prog_type;
|
||||
xattr.insns = insns;
|
||||
xattr.insns_cnt = insns_cnt;
|
||||
xattr.license = "GPL";
|
||||
xattr.prog_ifindex = ifindex;
|
||||
opts.prog_ifindex = ifindex;
|
||||
opts.log_buf = buf;
|
||||
opts.log_size = buf_len;
|
||||
|
||||
fd = bpf_load_program_xattr(&xattr, buf, buf_len);
|
||||
fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, NULL);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
@@ -203,7 +201,6 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
||||
{
|
||||
int key_size, value_size, max_entries, map_flags;
|
||||
__u32 btf_key_type_id = 0, btf_value_type_id = 0;
|
||||
struct bpf_create_map_attr attr = {};
|
||||
int fd = -1, btf_fd = -1, fd_inner;
|
||||
|
||||
key_size = sizeof(__u32);
|
||||
@@ -273,34 +270,35 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
||||
|
||||
if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
|
||||
map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||
|
||||
/* TODO: probe for device, once libbpf has a function to create
|
||||
* map-in-map for offload
|
||||
*/
|
||||
if (ifindex)
|
||||
return false;
|
||||
|
||||
fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
|
||||
sizeof(__u32), sizeof(__u32), 1, 0);
|
||||
fd_inner = bpf_map_create(BPF_MAP_TYPE_HASH, NULL,
|
||||
sizeof(__u32), sizeof(__u32), 1, NULL);
|
||||
if (fd_inner < 0)
|
||||
return false;
|
||||
fd = bpf_create_map_in_map(map_type, NULL, sizeof(__u32),
|
||||
fd_inner, 1, 0);
|
||||
|
||||
opts.inner_map_fd = fd_inner;
|
||||
fd = bpf_map_create(map_type, NULL, sizeof(__u32), sizeof(__u32), 1, &opts);
|
||||
close(fd_inner);
|
||||
} else {
|
||||
LIBBPF_OPTS(bpf_map_create_opts, opts);
|
||||
|
||||
/* Note: No other restriction on map type probes for offload */
|
||||
attr.map_type = map_type;
|
||||
attr.key_size = key_size;
|
||||
attr.value_size = value_size;
|
||||
attr.max_entries = max_entries;
|
||||
attr.map_flags = map_flags;
|
||||
attr.map_ifindex = ifindex;
|
||||
opts.map_flags = map_flags;
|
||||
opts.map_ifindex = ifindex;
|
||||
if (btf_fd >= 0) {
|
||||
attr.btf_fd = btf_fd;
|
||||
attr.btf_key_type_id = btf_key_type_id;
|
||||
attr.btf_value_type_id = btf_value_type_id;
|
||||
opts.btf_fd = btf_fd;
|
||||
opts.btf_key_type_id = btf_key_type_id;
|
||||
opts.btf_value_type_id = btf_value_type_id;
|
||||
}
|
||||
|
||||
fd = bpf_create_map_xattr(&attr);
|
||||
fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);
|
||||
}
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
55
src/linker.c
55
src/linker.c
@@ -15,7 +15,6 @@
|
||||
#include <linux/btf.h>
|
||||
#include <elf.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
#include <fcntl.h>
|
||||
#include "libbpf.h"
|
||||
#include "btf.h"
|
||||
@@ -211,6 +210,7 @@ void bpf_linker__free(struct bpf_linker *linker)
|
||||
}
|
||||
free(linker->secs);
|
||||
|
||||
free(linker->glob_syms);
|
||||
free(linker);
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ static int init_output_elf(struct bpf_linker *linker, const char *file)
|
||||
if (!linker->filename)
|
||||
return -ENOMEM;
|
||||
|
||||
linker->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
linker->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
|
||||
if (linker->fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to create '%s': %d\n", file, err);
|
||||
@@ -324,12 +324,12 @@ static int init_output_elf(struct bpf_linker *linker, const char *file)
|
||||
|
||||
linker->elf_hdr->e_machine = EM_BPF;
|
||||
linker->elf_hdr->e_type = ET_REL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
||||
#else
|
||||
#error "Unknown __BYTE_ORDER"
|
||||
#error "Unknown __BYTE_ORDER__"
|
||||
#endif
|
||||
|
||||
/* STRTAB */
|
||||
@@ -539,12 +539,12 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
||||
const struct bpf_linker_file_opts *opts,
|
||||
struct src_obj *obj)
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
const int host_endianness = ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
const int host_endianness = ELFDATA2MSB;
|
||||
#else
|
||||
#error "Unknown __BYTE_ORDER"
|
||||
#error "Unknown __BYTE_ORDER__"
|
||||
#endif
|
||||
int err = 0;
|
||||
Elf_Scn *scn;
|
||||
@@ -557,7 +557,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|
||||
|
||||
obj->filename = filename;
|
||||
|
||||
obj->fd = open(filename, O_RDONLY);
|
||||
obj->fd = open(filename, O_RDONLY | O_CLOEXEC);
|
||||
if (obj->fd < 0) {
|
||||
err = -errno;
|
||||
pr_warn("failed to open file '%s': %d\n", filename, err);
|
||||
@@ -921,7 +921,7 @@ static int check_btf_type_id(__u32 *type_id, void *ctx)
|
||||
{
|
||||
struct btf *btf = ctx;
|
||||
|
||||
if (*type_id > btf__get_nr_types(btf))
|
||||
if (*type_id >= btf__type_cnt(btf))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -948,8 +948,8 @@ static int linker_sanity_check_btf(struct src_obj *obj)
|
||||
if (!obj->btf)
|
||||
return 0;
|
||||
|
||||
n = btf__get_nr_types(obj->btf);
|
||||
for (i = 1; i <= n; i++) {
|
||||
n = btf__type_cnt(obj->btf);
|
||||
for (i = 1; i < n; i++) {
|
||||
t = btf_type_by_id(obj->btf, i);
|
||||
|
||||
err = err ?: btf_type_visit_type_ids(t, check_btf_type_id, obj->btf);
|
||||
@@ -1659,8 +1659,8 @@ static int find_glob_sym_btf(struct src_obj *obj, Elf64_Sym *sym, const char *sy
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = btf__get_nr_types(obj->btf);
|
||||
for (i = 1; i <= n; i++) {
|
||||
n = btf__type_cnt(obj->btf);
|
||||
for (i = 1; i < n; i++) {
|
||||
t = btf__type_by_id(obj->btf, i);
|
||||
|
||||
/* some global and extern FUNCs and VARs might not be associated with any
|
||||
@@ -2000,7 +2000,7 @@ add_sym:
|
||||
static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *obj)
|
||||
{
|
||||
struct src_sec *src_symtab = &obj->secs[obj->symtab_sec_idx];
|
||||
struct dst_sec *dst_symtab = &linker->secs[linker->symtab_sec_idx];
|
||||
struct dst_sec *dst_symtab;
|
||||
int i, err;
|
||||
|
||||
for (i = 1; i < obj->sec_cnt; i++) {
|
||||
@@ -2033,6 +2033,9 @@ static int linker_append_elf_relos(struct bpf_linker *linker, struct src_obj *ob
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add_dst_sec() above could have invalidated linker->secs */
|
||||
dst_symtab = &linker->secs[linker->symtab_sec_idx];
|
||||
|
||||
/* shdr->sh_link points to SYMTAB */
|
||||
dst_sec->shdr->sh_link = linker->symtab_sec_idx;
|
||||
|
||||
@@ -2131,8 +2134,8 @@ static int linker_fixup_btf(struct src_obj *obj)
|
||||
if (!obj->btf)
|
||||
return 0;
|
||||
|
||||
n = btf__get_nr_types(obj->btf);
|
||||
for (i = 1; i <= n; i++) {
|
||||
n = btf__type_cnt(obj->btf);
|
||||
for (i = 1; i < n; i++) {
|
||||
struct btf_var_secinfo *vi;
|
||||
struct btf_type *t;
|
||||
|
||||
@@ -2235,14 +2238,14 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
|
||||
if (!obj->btf)
|
||||
return 0;
|
||||
|
||||
start_id = btf__get_nr_types(linker->btf) + 1;
|
||||
n = btf__get_nr_types(obj->btf);
|
||||
start_id = btf__type_cnt(linker->btf);
|
||||
n = btf__type_cnt(obj->btf);
|
||||
|
||||
obj->btf_type_map = calloc(n + 1, sizeof(int));
|
||||
if (!obj->btf_type_map)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
for (i = 1; i < n; i++) {
|
||||
struct glob_sym *glob_sym = NULL;
|
||||
|
||||
t = btf__type_by_id(obj->btf, i);
|
||||
@@ -2297,8 +2300,8 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
|
||||
}
|
||||
|
||||
/* remap all the types except DATASECs */
|
||||
n = btf__get_nr_types(linker->btf);
|
||||
for (i = start_id; i <= n; i++) {
|
||||
n = btf__type_cnt(linker->btf);
|
||||
for (i = start_id; i < n; i++) {
|
||||
struct btf_type *dst_t = btf_type_by_id(linker->btf, i);
|
||||
|
||||
if (btf_type_visit_type_ids(dst_t, remap_type_id, obj->btf_type_map))
|
||||
@@ -2651,13 +2654,14 @@ static int emit_elf_data_sec(struct bpf_linker *linker, const char *sec_name,
|
||||
|
||||
static int finalize_btf(struct bpf_linker *linker)
|
||||
{
|
||||
LIBBPF_OPTS(btf_dedup_opts, opts);
|
||||
struct btf *btf = linker->btf;
|
||||
const void *raw_data;
|
||||
int i, j, id, err;
|
||||
__u32 raw_sz;
|
||||
|
||||
/* bail out if no BTF data was produced */
|
||||
if (btf__get_nr_types(linker->btf) == 0)
|
||||
if (btf__type_cnt(linker->btf) == 1)
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < linker->sec_cnt; i++) {
|
||||
@@ -2687,14 +2691,15 @@ static int finalize_btf(struct bpf_linker *linker)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = btf__dedup(linker->btf, linker->btf_ext, NULL);
|
||||
opts.btf_ext = linker->btf_ext;
|
||||
err = btf__dedup(linker->btf, &opts);
|
||||
if (err) {
|
||||
pr_warn("BTF dedup failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Emit .BTF section */
|
||||
raw_data = btf__get_raw_data(linker->btf, &raw_sz);
|
||||
raw_data = btf__raw_data(linker->btf, &raw_sz);
|
||||
if (!raw_data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -662,7 +662,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
|
||||
*validate = true; /* signedness is never ambiguous */
|
||||
break;
|
||||
case BPF_FIELD_LSHIFT_U64:
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
*val = 64 - (bit_off + bit_sz - byte_off * 8);
|
||||
#else
|
||||
*val = (8 - byte_sz) * 8 + (bit_off - byte_off * 8);
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef __NR_bpf
|
||||
# if defined(__mips__) && defined(_ABIO32)
|
||||
# define __NR_bpf 4355
|
||||
# elif defined(__mips__) && defined(_ABIN32)
|
||||
# define __NR_bpf 6319
|
||||
# elif defined(__mips__) && defined(_ABI64)
|
||||
# define __NR_bpf 5315
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* This file is a base header for auto-generated *.lskel.h files.
|
||||
* Its contents will change and may become part of auto-generation in the future.
|
||||
*
|
||||
@@ -65,8 +75,7 @@ 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);
|
||||
map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1, NULL);
|
||||
if (map_fd < 0) {
|
||||
opts->errstr = "failed to create loader map";
|
||||
err = -errno;
|
||||
|
||||
58
src/xsk.c
58
src/xsk.c
@@ -35,6 +35,11 @@
|
||||
#include "libbpf_internal.h"
|
||||
#include "xsk.h"
|
||||
|
||||
/* entire xsk.h and xsk.c is going away in libbpf 1.0, so ignore all internal
|
||||
* uses of deprecated APIs
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
#ifndef SOL_XDP
|
||||
#define SOL_XDP 283
|
||||
#endif
|
||||
@@ -300,7 +305,7 @@ int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
if (!umem)
|
||||
return -ENOMEM;
|
||||
|
||||
umem->fd = socket(AF_XDP, SOCK_RAW, 0);
|
||||
umem->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
|
||||
if (umem->fd < 0) {
|
||||
err = -errno;
|
||||
goto out_umem_alloc;
|
||||
@@ -364,8 +369,6 @@ int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
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[] = {
|
||||
@@ -375,27 +378,15 @@ static enum xsk_prog get_xsk_prog(void)
|
||||
BPF_EMIT_CALL(BPF_FUNC_redirect_map),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int prog_fd, map_fd, ret;
|
||||
int prog_fd, map_fd, ret, insn_cnt = ARRAY_SIZE(insns);
|
||||
|
||||
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);
|
||||
map_fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, NULL, sizeof(int), sizeof(int), 1, NULL);
|
||||
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);
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
|
||||
if (prog_fd < 0) {
|
||||
close(map_fd);
|
||||
return detected;
|
||||
@@ -495,10 +486,13 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||
};
|
||||
struct bpf_insn *progs[] = {prog, prog_redirect_flags};
|
||||
enum xsk_prog option = get_xsk_prog();
|
||||
LIBBPF_OPTS(bpf_prog_load_opts, opts,
|
||||
.log_buf = log_buf,
|
||||
.log_size = log_buf_size,
|
||||
);
|
||||
|
||||
prog_fd = bpf_load_program(BPF_PROG_TYPE_XDP, progs[option], insns_cnt[option],
|
||||
"LGPL-2.1 or BSD-2-Clause", 0, log_buf,
|
||||
log_buf_size);
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "LGPL-2.1 or BSD-2-Clause",
|
||||
progs[option], insns_cnt[option], &opts);
|
||||
if (prog_fd < 0) {
|
||||
pr_warn("BPF log buffer:\n%s", log_buf);
|
||||
return prog_fd;
|
||||
@@ -549,7 +543,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
|
||||
struct ifreq ifr = {};
|
||||
int fd, err, ret;
|
||||
|
||||
fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
fd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -590,8 +584,8 @@ static int xsk_create_bpf_maps(struct xsk_socket *xsk)
|
||||
if (max_queues < 0)
|
||||
return max_queues;
|
||||
|
||||
fd = bpf_create_map_name(BPF_MAP_TYPE_XSKMAP, "xsks_map",
|
||||
sizeof(int), sizeof(int), max_queues, 0);
|
||||
fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, "xsks_map",
|
||||
sizeof(int), sizeof(int), max_queues, NULL);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
@@ -725,14 +719,12 @@ static int xsk_link_lookup(int ifindex, __u32 *prog_id, int *link_fd)
|
||||
|
||||
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;
|
||||
LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = XDP_FLAGS_SKB_MODE);
|
||||
struct bpf_insn insns[2] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
|
||||
BPF_EXIT_INSN()
|
||||
};
|
||||
int prog_fd, link_fd = -1;
|
||||
int prog_fd, link_fd = -1, insn_cnt = ARRAY_SIZE(insns);
|
||||
int ifindex_lo = 1;
|
||||
bool ret = false;
|
||||
int err;
|
||||
@@ -744,13 +736,7 @@ static bool xsk_probe_bpf_link(void)
|
||||
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);
|
||||
prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
|
||||
if (prog_fd < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1046,7 +1032,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
||||
}
|
||||
|
||||
if (umem->refcount++ > 0) {
|
||||
xsk->fd = socket(AF_XDP, SOCK_RAW, 0);
|
||||
xsk->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
|
||||
if (xsk->fd < 0) {
|
||||
err = -errno;
|
||||
goto out_xsk_alloc;
|
||||
|
||||
90
src/xsk.h
90
src/xsk.h
@@ -23,6 +23,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This whole API has been deprecated and moved to libxdp that can be found at
|
||||
* https://github.com/xdp-project/xdp-tools. The APIs are exactly the same so
|
||||
* it should just be linking with libxdp instead of libbpf for this set of
|
||||
* functionality. If not, please submit a bug report on the aforementioned page.
|
||||
*/
|
||||
|
||||
/* Load-Acquire Store-Release barriers used by the XDP socket
|
||||
* library. The following macros should *NOT* be considered part of
|
||||
* the xsk.h API, and is subject to change anytime.
|
||||
@@ -245,8 +251,10 @@ static inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)
|
||||
return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);
|
||||
}
|
||||
|
||||
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
||||
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__fd(const struct xsk_umem *umem);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
|
||||
#define XSK_RING_CONS__DEFAULT_NUM_DESCS 2048
|
||||
#define XSK_RING_PROD__DEFAULT_NUM_DESCS 2048
|
||||
@@ -263,10 +271,10 @@ struct xsk_umem_config {
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
LIBBPF_API int xsk_setup_xdp_prog(int ifindex,
|
||||
int *xsks_map_fd);
|
||||
LIBBPF_API int xsk_socket__update_xskmap(struct xsk_socket *xsk,
|
||||
int xsks_map_fd);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_setup_xdp_prog(int ifindex, int *xsks_map_fd);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__update_xskmap(struct xsk_socket *xsk, int xsks_map_fd);
|
||||
|
||||
/* Flags for the libbpf_flags field. */
|
||||
#define XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD (1 << 0)
|
||||
@@ -280,40 +288,46 @@ struct xsk_socket_config {
|
||||
};
|
||||
|
||||
/* Set config to NULL to get the default configuration. */
|
||||
LIBBPF_API int xsk_umem__create(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
||||
const char *ifname, __u32 queue_id,
|
||||
struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
const struct xsk_socket_config *config);
|
||||
LIBBPF_API int
|
||||
xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
||||
const char *ifname,
|
||||
__u32 queue_id, struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_socket_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__create(struct xsk_socket **xsk,
|
||||
const char *ifname, __u32 queue_id,
|
||||
struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
const struct xsk_socket_config *config);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
|
||||
const char *ifname,
|
||||
__u32 queue_id, struct xsk_umem *umem,
|
||||
struct xsk_ring_cons *rx,
|
||||
struct xsk_ring_prod *tx,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_socket_config *config);
|
||||
|
||||
/* Returns 0 for success and -EBUSY if the umem is still in use. */
|
||||
LIBBPF_API int xsk_umem__delete(struct xsk_umem *umem);
|
||||
LIBBPF_API void xsk_socket__delete(struct xsk_socket *xsk);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
int xsk_umem__delete(struct xsk_umem *umem);
|
||||
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "AF_XDP support deprecated and moved to libxdp")
|
||||
void xsk_socket__delete(struct xsk_socket *xsk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,7 +6,7 @@ source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||
|
||||
travis_fold start prepare_selftests "Building selftests"
|
||||
|
||||
sudo apt-get -y install python-docutils # for rst2man
|
||||
sudo apt-get -y install python3-docutils # for rst2man
|
||||
|
||||
LLVM_VER=14
|
||||
LIBBPF_PATH="${REPO_ROOT}"
|
||||
@@ -37,6 +37,6 @@ cd ${LIBBPF_PATH}
|
||||
rm selftests/bpf/.gitignore
|
||||
git add selftests
|
||||
|
||||
git add "${VMTEST_ROOT}/configs/blacklist"
|
||||
git add "${VMTEST_ROOT}"/configs/blacklist/BLACKLIST-* "${VMTEST_ROOT}"/configs/whitelist/WHITELIST-*
|
||||
|
||||
travis_fold end prepare_selftests
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
INDEX https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/INDEX
|
||||
libbpf-vmtest-rootfs-2020.09.27.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.09.27.tar.zst
|
||||
vmlinux-4.9.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-4.9.0.zst
|
||||
vmlinux-5.5.0-rc6.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0-rc6.zst
|
||||
vmlinux-5.5.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0.zst
|
||||
vmlinuz-5.5.0-rc6 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0-rc6
|
||||
vmlinuz-5.5.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0
|
||||
vmlinuz-4.9.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-4.9.0
|
||||
x86_64/libbpf-vmtest-rootfs-2020.09.27.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.09.27.tar.zst
|
||||
x86_64/vmlinux-4.9.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-4.9.0.zst
|
||||
x86_64/vmlinux-5.5.0-rc6.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0-rc6.zst
|
||||
x86_64/vmlinux-5.5.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0.zst
|
||||
x86_64/vmlinuz-5.5.0-rc6 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0-rc6
|
||||
x86_64/vmlinuz-5.5.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0
|
||||
x86_64/vmlinuz-4.9.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-4.9.0
|
||||
s390x/libbpf-vmtest-rootfs-2021.03.24.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/s390x/libbpf-vmtest-rootfs-2021.03.24.tar.zst
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# This file is not used and is there for historic purposes only.
|
||||
# See WHITELIST-5.5.0 instead.
|
||||
|
||||
# PERMANENTLY DISABLED
|
||||
align # verifier output format changed
|
||||
atomics # new atomic operations (v5.12+)
|
||||
|
||||
52
travis-ci/vmtest/configs/blacklist/BLACKLIST-latest.s390x
Normal file
52
travis-ci/vmtest/configs/blacklist/BLACKLIST-latest.s390x
Normal file
@@ -0,0 +1,52 @@
|
||||
# TEMPORARY
|
||||
atomics # attach(add): actual -524 <= expected 0 (trampoline)
|
||||
bpf_iter_setsockopt # JIT does not support calling kernel function (kfunc)
|
||||
bloom_filter_map # failed to find kernel BTF type ID of '__x64_sys_getpgid': -3 (?)
|
||||
bpf_tcp_ca # JIT does not support calling kernel function (kfunc)
|
||||
core_read_macros # unknown func bpf_probe_read#4 (overlapping)
|
||||
d_path # failed to auto-attach program 'prog_stat': -524 (trampoline)
|
||||
dummy_st_ops # test_run unexpected error: -524 (errno 524) (trampoline)
|
||||
fentry_fexit # fentry attach failed: -524 (trampoline)
|
||||
fentry_test # fentry_first_attach unexpected error: -524 (trampoline)
|
||||
fexit_bpf2bpf # freplace_attach_trace unexpected error: -524 (trampoline)
|
||||
fexit_sleep # fexit_skel_load fexit skeleton failed (trampoline)
|
||||
fexit_stress # fexit attach failed prog 0 failed: -524 (trampoline)
|
||||
fexit_test # fexit_first_attach unexpected error: -524 (trampoline)
|
||||
get_func_ip_test # get_func_ip_test__attach unexpected error: -524 (trampoline)
|
||||
get_stack_raw_tp # user_stack corrupted user stack (no backchain userspace)
|
||||
kfree_skb # attach fentry unexpected error: -524 (trampoline)
|
||||
kfunc_call # 'bpf_prog_active': not found in kernel BTF (?)
|
||||
ksyms_module # test_ksyms_module__open_and_load unexpected error: -9 (?)
|
||||
ksyms_module_libbpf # JIT does not support calling kernel function (kfunc)
|
||||
ksyms_module_lskel # test_ksyms_module_lskel__open_and_load unexpected error: -9 (?)
|
||||
modify_return # modify_return attach failed: -524 (trampoline)
|
||||
module_attach # skel_attach skeleton attach failed: -524 (trampoline)
|
||||
netcnt # failed to load BPF skeleton 'netcnt_prog': -7 (?)
|
||||
probe_user # check_kprobe_res wrong kprobe res from probe read (?)
|
||||
recursion # skel_attach unexpected error: -524 (trampoline)
|
||||
ringbuf # skel_load skeleton load failed (?)
|
||||
sk_assign # Can't read on server: Invalid argument (?)
|
||||
sk_storage_tracing # test_sk_storage_tracing__attach unexpected error: -524 (trampoline)
|
||||
skc_to_unix_sock # could not attach BPF object unexpected error: -524 (trampoline)
|
||||
socket_cookie # prog_attach unexpected error: -524 (trampoline)
|
||||
stacktrace_build_id # compare_map_keys stackid_hmap vs. stackmap err -2 errno 2 (?)
|
||||
tailcalls # tail_calls are not allowed in non-JITed programs with bpf-to-bpf calls (?)
|
||||
task_local_storage # failed to auto-attach program 'trace_exit_creds': -524 (trampoline)
|
||||
test_bpffs # bpffs test failed 255 (iterator)
|
||||
test_bprm_opts # failed to auto-attach program 'secure_exec': -524 (trampoline)
|
||||
test_ima # failed to auto-attach program 'ima': -524 (trampoline)
|
||||
test_local_storage # failed to auto-attach program 'unlink_hook': -524 (trampoline)
|
||||
test_lsm # failed to find kernel BTF type ID of '__x64_sys_setdomainname': -3 (?)
|
||||
test_overhead # attach_fentry unexpected error: -524 (trampoline)
|
||||
test_profiler # unknown func bpf_probe_read_str#45 (overlapping)
|
||||
timer # failed to auto-attach program 'test1': -524 (trampoline)
|
||||
timer_mim # failed to auto-attach program 'test1': -524 (trampoline)
|
||||
trace_ext # failed to auto-attach program 'test_pkt_md_access_new': -524 (trampoline)
|
||||
trace_printk # trace_printk__load unexpected error: -2 (errno 2) (?)
|
||||
trace_vprintk # trace_vprintk__open_and_load unexpected error: -9 (?)
|
||||
trampoline_count # prog 'prog1': failed to attach: ERROR: strerror_r(-524)=22 (trampoline)
|
||||
verif_stats # trace_vprintk__open_and_load unexpected error: -9 (?)
|
||||
vmlinux # failed to auto-attach program 'handle__fentry': -524 (trampoline)
|
||||
xdp_adjust_tail # case-128 err 0 errno 28 retval 1 size 128 expect-size 3520 (?)
|
||||
xdp_bonding # failed to auto-attach program 'trace_on_entry': -524 (trampoline)
|
||||
xdp_bpf2bpf # failed to auto-attach program 'trace_on_entry': -524 (trampoline)
|
||||
2703
travis-ci/vmtest/configs/config-latest.s390x
Normal file
2703
travis-ci/vmtest/configs/config-latest.s390x
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
core_retro
|
||||
cpu_mask
|
||||
hashmap
|
||||
legacy_printk
|
||||
perf_buffer
|
||||
section_names
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ global_data_init
|
||||
global_func_args
|
||||
hashmap
|
||||
l4lb_all
|
||||
legacy_printk
|
||||
linked_funcs
|
||||
linked_maps
|
||||
map_lock
|
||||
|
||||
@@ -22,3 +22,25 @@ travis_fold() {
|
||||
echo -e "$line"
|
||||
fi
|
||||
}
|
||||
|
||||
ARCH=$(uname -m)
|
||||
|
||||
__print() {
|
||||
local TITLE=""
|
||||
if [[ -n $2 ]]; then
|
||||
TITLE=" title=$2"
|
||||
fi
|
||||
echo "::$1${TITLE}::$3"
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_error() {
|
||||
__print error $1 $2
|
||||
}
|
||||
|
||||
# $1 - title
|
||||
# $2 - message
|
||||
print_notice() {
|
||||
__print notice $1 $2
|
||||
}
|
||||
|
||||
@@ -100,59 +100,7 @@ rm -rf "$root/var/lib/pacman/sync/"
|
||||
# We don't need any documentation.
|
||||
rm -rf "$root/usr/share/{doc,help,man,texinfo}"
|
||||
|
||||
chroot "${root}" /bin/busybox --install
|
||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
||||
|
||||
cat > "$root/etc/inittab" << "EOF"
|
||||
::sysinit:/etc/init.d/rcS
|
||||
::ctrlaltdel:/sbin/reboot
|
||||
::shutdown:/sbin/swapoff -a
|
||||
::shutdown:/bin/umount -a -r
|
||||
::restart:/sbin/init
|
||||
EOF
|
||||
chmod 644 "$root/etc/inittab"
|
||||
|
||||
mkdir -m 755 "$root/etc/init.d" "$root/etc/rcS.d"
|
||||
cat > "$root/etc/rcS.d/S10-mount" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
/bin/mount proc /proc -t proc
|
||||
|
||||
# Mount devtmpfs if not mounted
|
||||
if [[ -z $(/bin/mount -l -t devtmpfs) ]]; then
|
||||
/bin/mount devtmpfs /dev -t devtmpfs
|
||||
fi
|
||||
|
||||
/bin/mount sysfs /sys -t sysfs
|
||||
/bin/mount bpffs /sys/fs/bpf -t bpf
|
||||
/bin/mount debugfs /sys/kernel/debug -t debugfs
|
||||
|
||||
echo 'Listing currently mounted file systems'
|
||||
/bin/mount
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
||||
|
||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
ip link set lo up
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
||||
|
||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
for path in /etc/rcS.d/S*; do
|
||||
[ -x "$path" ] && "$path"
|
||||
done
|
||||
EOF
|
||||
chmod 755 "$root/etc/init.d/rcS"
|
||||
|
||||
chmod 755 "$root"
|
||||
tar -C "$root" -c . | zstd -T0 -19 -o "$NAME"
|
||||
chmod 644 "$NAME"
|
||||
40
travis-ci/vmtest/mkrootfs_debian.sh
Executable file
40
travis-ci/vmtest/mkrootfs_debian.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
# This script builds a Debian root filesystem image for testing libbpf in a
|
||||
# virtual machine. Requires debootstrap >= 1.0.95 and zstd.
|
||||
|
||||
set -e -u -x -o pipefail
|
||||
|
||||
# Check whether we are root now in order to avoid confusing errors later.
|
||||
if [ "$(id -u)" != 0 ]; then
|
||||
echo "$0 must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a working directory and schedule its deletion.
|
||||
root=$(mktemp -d -p "$PWD")
|
||||
trap 'rm -r "$root"' EXIT
|
||||
|
||||
# Install packages.
|
||||
packages=binutils,busybox,elfutils,iproute2,libcap2,libelf1,strace,zlib1g
|
||||
debootstrap --include="$packages" --variant=minbase bullseye "$root"
|
||||
|
||||
# Remove the init scripts (tests use their own). Also remove various
|
||||
# unnecessary files in order to save space.
|
||||
rm -rf \
|
||||
"$root"/etc/rcS.d \
|
||||
"$root"/usr/share/{doc,info,locale,man,zoneinfo} \
|
||||
"$root"/var/cache/apt/archives/* \
|
||||
"$root"/var/lib/apt/lists/*
|
||||
|
||||
# Save some more space by removing coreutils - the tests use busybox. Before
|
||||
# doing that, delete the buggy postrm script, which uses the rm command.
|
||||
rm -f "$root/var/lib/dpkg/info/coreutils.postrm"
|
||||
chroot "$root" dpkg --remove --force-remove-essential coreutils
|
||||
|
||||
# Apply common tweaks.
|
||||
"$(dirname "$0")"/mkrootfs_tweak.sh "$root"
|
||||
|
||||
# Save the result.
|
||||
name="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
||||
rm -f "$name"
|
||||
tar -C "$root" -c . | zstd -T0 -19 -o "$name"
|
||||
61
travis-ci/vmtest/mkrootfs_tweak.sh
Executable file
61
travis-ci/vmtest/mkrootfs_tweak.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
# This script prepares a mounted root filesystem for testing libbpf in a virtual
|
||||
# machine.
|
||||
set -e -u -x -o pipefail
|
||||
root=$1
|
||||
shift
|
||||
|
||||
chroot "${root}" /bin/busybox --install
|
||||
|
||||
cat > "$root/etc/inittab" << "EOF"
|
||||
::sysinit:/etc/init.d/rcS
|
||||
::ctrlaltdel:/sbin/reboot
|
||||
::shutdown:/sbin/swapoff -a
|
||||
::shutdown:/bin/umount -a -r
|
||||
::restart:/sbin/init
|
||||
EOF
|
||||
chmod 644 "$root/etc/inittab"
|
||||
|
||||
mkdir -m 755 -p "$root/etc/init.d" "$root/etc/rcS.d"
|
||||
cat > "$root/etc/rcS.d/S10-mount" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
/bin/mount proc /proc -t proc
|
||||
|
||||
# Mount devtmpfs if not mounted
|
||||
if [[ -z $(/bin/mount -l -t devtmpfs) ]]; then
|
||||
/bin/mount devtmpfs /dev -t devtmpfs
|
||||
fi
|
||||
|
||||
/bin/mount sysfs /sys -t sysfs
|
||||
/bin/mount bpffs /sys/fs/bpf -t bpf
|
||||
/bin/mount debugfs /sys/kernel/debug -t debugfs
|
||||
|
||||
echo 'Listing currently mounted file systems'
|
||||
/bin/mount
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
||||
|
||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
ip link set lo up
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
||||
|
||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
for path in /etc/rcS.d/S*; do
|
||||
[ -x "$path" ] && "$path"
|
||||
done
|
||||
EOF
|
||||
chmod 755 "$root/etc/init.d/rcS"
|
||||
|
||||
chmod 755 "$root"
|
||||
@@ -14,7 +14,7 @@ fi
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
travis_fold start build_kernel "Kernel build"
|
||||
|
||||
cp ${VMTEST_ROOT}/configs/latest.config .config
|
||||
cp "$VMTEST_ROOT"/configs/config-latest."$ARCH" .config
|
||||
make -j $((4*$(nproc))) olddefconfig all >/dev/null
|
||||
travis_fold end build_kernel
|
||||
fi
|
||||
|
||||
@@ -15,7 +15,7 @@ Run "${PROJECT_NAME}" tests in a virtual machine.
|
||||
This exits with status 0 on success, 1 if the virtual machine ran successfully
|
||||
but tests failed, and 2 if we encountered a fatal error.
|
||||
|
||||
This script uses sudo to mount and modify the disk image.
|
||||
This script uses sudo to work around a libguestfs bug.
|
||||
|
||||
Arguments:
|
||||
IMG path of virtual machine disk image to create
|
||||
@@ -177,6 +177,11 @@ else
|
||||
fi
|
||||
IMG="${!OPTIND}"
|
||||
fi
|
||||
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
||||
img_size=2G
|
||||
else
|
||||
img_size=8G
|
||||
fi
|
||||
|
||||
unset URLS
|
||||
cache_urls() {
|
||||
@@ -194,7 +199,7 @@ matching_kernel_releases() {
|
||||
local pattern="$1"
|
||||
{
|
||||
for file in "${!URLS[@]}"; do
|
||||
if [[ $file =~ ^vmlinux-(.*).zst$ ]]; then
|
||||
if [[ $file =~ ^${ARCH}/vmlinux-(.*).zst$ ]]; then
|
||||
release="${BASH_REMATCH[1]}"
|
||||
case "$release" in
|
||||
$pattern)
|
||||
@@ -211,7 +216,7 @@ matching_kernel_releases() {
|
||||
newest_rootfs_version() {
|
||||
{
|
||||
for file in "${!URLS[@]}"; do
|
||||
if [[ $file =~ ^${PROJECT_NAME}-vmtest-rootfs-(.*)\.tar\.zst$ ]]; then
|
||||
if [[ $file =~ ^${ARCH}/${PROJECT_NAME}-vmtest-rootfs-(.*)\.tar\.zst$ ]]; then
|
||||
echo "${BASH_REMATCH[1]}"
|
||||
fi
|
||||
done
|
||||
@@ -242,15 +247,29 @@ cp_img() {
|
||||
create_rootfs_img() {
|
||||
local path="$1"
|
||||
set_nocow "$path"
|
||||
truncate -s 2G "$path"
|
||||
truncate -s "$img_size" "$path"
|
||||
mkfs.ext4 -q "$path"
|
||||
}
|
||||
|
||||
download_rootfs() {
|
||||
local rootfsversion="$1"
|
||||
local dir="$2"
|
||||
download "${PROJECT_NAME}-vmtest-rootfs-$rootfsversion.tar.zst" |
|
||||
zstd -d | sudo tar -C "$dir" -x
|
||||
download "${ARCH}/${PROJECT_NAME}-vmtest-rootfs-$rootfsversion.tar.zst" |
|
||||
zstd -d
|
||||
}
|
||||
|
||||
tar_in() {
|
||||
local dst_path="$1"
|
||||
# guestfish --remote does not forward file descriptors, which prevents
|
||||
# us from using `tar-in -` or bash process substitution. We don't want
|
||||
# to copy all the data into a temporary file, so use a FIFO.
|
||||
tmp=$(mktemp -d)
|
||||
mkfifo "$tmp/fifo"
|
||||
cat >"$tmp/fifo" &
|
||||
local cat_pid=$!
|
||||
guestfish --remote tar-in "$tmp/fifo" "$dst_path"
|
||||
wait "$cat_pid"
|
||||
rm -r "$tmp"
|
||||
tmp=
|
||||
}
|
||||
|
||||
if (( LIST )); then
|
||||
@@ -282,11 +301,11 @@ if [[ $SKIPIMG -eq 0 && ! -v ROOTFSVERSION ]]; then
|
||||
ROOTFSVERSION="$(newest_rootfs_version)"
|
||||
fi
|
||||
|
||||
travis_fold start vmlinux_setup "Preparing Linux image"
|
||||
|
||||
echo "Kernel release: $KERNELRELEASE" >&2
|
||||
echo
|
||||
|
||||
travis_fold start vmlinux_setup "Preparing Linux image"
|
||||
|
||||
if (( SKIPIMG )); then
|
||||
echo "Not extracting root filesystem" >&2
|
||||
else
|
||||
@@ -295,20 +314,14 @@ fi
|
||||
echo "Disk image: $IMG" >&2
|
||||
|
||||
tmp=
|
||||
ARCH_DIR="$DIR/x86_64"
|
||||
ARCH_DIR="$DIR/$ARCH"
|
||||
mkdir -p "$ARCH_DIR"
|
||||
mnt="$(mktemp -d -p "$DIR" mnt.XXXXXXXXXX)"
|
||||
|
||||
cleanup() {
|
||||
if [[ -n $tmp ]]; then
|
||||
rm -f "$tmp" || true
|
||||
fi
|
||||
if mountpoint -q "$mnt"; then
|
||||
sudo umount "$mnt" || true
|
||||
fi
|
||||
if [[ -d "$mnt" ]]; then
|
||||
rmdir "$mnt" || true
|
||||
rm -rf "$tmp" || true
|
||||
fi
|
||||
guestfish --remote exit 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
@@ -318,18 +331,25 @@ else
|
||||
vmlinuz="${ARCH_DIR}/vmlinuz-${KERNELRELEASE}"
|
||||
if [[ ! -e $vmlinuz ]]; then
|
||||
tmp="$(mktemp "$vmlinuz.XXX.part")"
|
||||
download "vmlinuz-${KERNELRELEASE}" -o "$tmp"
|
||||
download "${ARCH}/vmlinuz-${KERNELRELEASE}" -o "$tmp"
|
||||
mv "$tmp" "$vmlinuz"
|
||||
tmp=
|
||||
fi
|
||||
fi
|
||||
|
||||
# Mount and set up the rootfs image.
|
||||
# Mount and set up the rootfs image. Use a persistent guestfish session in
|
||||
# order to avoid the startup overhead.
|
||||
# Work around https://bugs.launchpad.net/fuel/+bug/1467579.
|
||||
sudo chmod +r /boot/vmlinuz*
|
||||
eval "$(guestfish --listen)"
|
||||
if (( ONESHOT )); then
|
||||
rm -f "$IMG"
|
||||
create_rootfs_img "$IMG"
|
||||
sudo mount -o loop "$IMG" "$mnt"
|
||||
download_rootfs "$ROOTFSVERSION" "$mnt"
|
||||
guestfish --remote \
|
||||
add "$IMG" label:img : \
|
||||
launch : \
|
||||
mount /dev/disk/guestfs/img /
|
||||
download_rootfs "$ROOTFSVERSION" | tar_in /
|
||||
else
|
||||
if (( ! SKIPIMG )); then
|
||||
rootfs_img="${ARCH_DIR}/${PROJECT_NAME}-vmtest-rootfs-${ROOTFSVERSION}.img"
|
||||
@@ -337,13 +357,15 @@ else
|
||||
if [[ ! -e $rootfs_img ]]; then
|
||||
tmp="$(mktemp "$rootfs_img.XXX.part")"
|
||||
set_nocow "$tmp"
|
||||
truncate -s 2G "$tmp"
|
||||
truncate -s "$img_size" "$tmp"
|
||||
mkfs.ext4 -q "$tmp"
|
||||
sudo mount -o loop "$tmp" "$mnt"
|
||||
|
||||
download_rootfs "$ROOTFSVERSION" "$mnt"
|
||||
# libguestfs supports hotplugging only with a libvirt
|
||||
# backend, which we are not using here, so handle the
|
||||
# temporary image in a separate session.
|
||||
download_rootfs "$ROOTFSVERSION" |
|
||||
guestfish -a "$tmp" tar-in - /
|
||||
|
||||
sudo umount "$mnt"
|
||||
mv "$tmp" "$rootfs_img"
|
||||
tmp=
|
||||
fi
|
||||
@@ -351,11 +373,14 @@ else
|
||||
rm -f "$IMG"
|
||||
cp_img "$rootfs_img" "$IMG"
|
||||
fi
|
||||
sudo mount -o loop "$IMG" "$mnt"
|
||||
guestfish --remote \
|
||||
add "$IMG" label:img : \
|
||||
launch : \
|
||||
mount /dev/disk/guestfs/img /
|
||||
fi
|
||||
|
||||
# Install vmlinux.
|
||||
vmlinux="$mnt/boot/vmlinux-${KERNELRELEASE}"
|
||||
vmlinux="/boot/vmlinux-${KERNELRELEASE}"
|
||||
if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
||||
if [[ -v BUILDDIR ]]; then
|
||||
source_vmlinux="${BUILDDIR}/vmlinux"
|
||||
@@ -363,20 +388,19 @@ if [[ -v BUILDDIR || $ONESHOT -eq 0 ]]; then
|
||||
source_vmlinux="${ARCH_DIR}/vmlinux-${KERNELRELEASE}"
|
||||
if [[ ! -e $source_vmlinux ]]; then
|
||||
tmp="$(mktemp "$source_vmlinux.XXX.part")"
|
||||
download "vmlinux-${KERNELRELEASE}.zst" | zstd -dfo "$tmp"
|
||||
download "${ARCH}/vmlinux-${KERNELRELEASE}.zst" | zstd -dfo "$tmp"
|
||||
mv "$tmp" "$source_vmlinux"
|
||||
tmp=
|
||||
fi
|
||||
fi
|
||||
echo "Copying vmlinux..." >&2
|
||||
sudo rsync -cp --chmod 0644 "$source_vmlinux" "$vmlinux"
|
||||
else
|
||||
# We could use "sudo zstd -o", but let's not run zstd as root with
|
||||
# input from the internet.
|
||||
download "vmlinux-${KERNELRELEASE}.zst" |
|
||||
zstd -d | sudo tee "$vmlinux" > /dev/null
|
||||
sudo chmod 644 "$vmlinux"
|
||||
source_vmlinux="${ARCH_DIR}/vmlinux-${KERNELRELEASE}"
|
||||
download "${ARCH}/vmlinux-${KERNELRELEASE}.zst" | zstd -d >"$source_vmlinux"
|
||||
fi
|
||||
echo "Copying vmlinux..." >&2
|
||||
guestfish --remote \
|
||||
upload "$source_vmlinux" "$vmlinux" : \
|
||||
chmod 644 "$vmlinux"
|
||||
|
||||
travis_fold end vmlinux_setup
|
||||
|
||||
@@ -384,14 +408,24 @@ REPO_PATH="${SELFTEST_REPO_PATH:-travis-ci/vmtest/bpf-next}"
|
||||
LIBBPF_PATH="${REPO_ROOT}" \
|
||||
VMTEST_ROOT="${VMTEST_ROOT}" \
|
||||
REPO_PATH="${REPO_PATH}" \
|
||||
VMLINUX_BTF=${vmlinux} ${VMTEST_ROOT}/build_selftests.sh
|
||||
VMLINUX_BTF=$(realpath ${source_vmlinux}) ${VMTEST_ROOT}/build_selftests.sh
|
||||
|
||||
travis_fold start bpftool_checks "Running bpftool checks..."
|
||||
bpftool_exitstatus=
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
"${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf/test_bpftool_synctypes.py" && \
|
||||
echo "Consistency checks passed successfully."
|
||||
# "&& true" does not change the return code (it is not executed if the
|
||||
# Python script fails), but it prevents the trap on ERR set at the top
|
||||
# of this file to trigger on failure.
|
||||
"${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf/test_bpftool_synctypes.py" && true
|
||||
bpftool_exitstatus=$?
|
||||
if [[ "$bpftool_exitstatus" -eq 0 ]]; then
|
||||
print_notice bpftool_checks "bpftool checks passed successfully."
|
||||
else
|
||||
print_error bpftool_checks "bpftool checks returned ${bpftool_exitstatus}."
|
||||
fi
|
||||
bpftool_exitstatus="bpftool:${bpftool_exitstatus}"
|
||||
else
|
||||
echo "Consistency checks skipped."
|
||||
echo "bpftool checks skipped."
|
||||
fi
|
||||
travis_fold end bpftool_checks
|
||||
|
||||
@@ -402,23 +436,31 @@ if (( SKIPSOURCE )); then
|
||||
else
|
||||
echo "Copying source files..." >&2
|
||||
# Copy the source files in.
|
||||
sudo mkdir -p -m 0755 "$mnt/${PROJECT_NAME}"
|
||||
guestfish --remote \
|
||||
mkdir-p "/${PROJECT_NAME}" : \
|
||||
chmod 0755 "/${PROJECT_NAME}"
|
||||
if [[ "${SOURCE_FULLCOPY}" == "1" ]]; then
|
||||
git ls-files -z | sudo rsync --files-from=- -0cpt . "$mnt/${PROJECT_NAME}"
|
||||
git ls-files -z | tar --null --files-from=- -c | tar_in "/${PROJECT_NAME}"
|
||||
else
|
||||
sudo mkdir -p -m 0755 ${mnt}/${PROJECT_NAME}/{selftests,travis-ci}
|
||||
guestfish --remote \
|
||||
mkdir-p "/${PROJECT_NAME}/selftests" : \
|
||||
chmod 0755 "/${PROJECT_NAME}/selftests" : \
|
||||
mkdir-p "/${PROJECT_NAME}/travis-ci" : \
|
||||
chmod 0755 "/${PROJECT_NAME}/travis-ci"
|
||||
tree --du -shaC "${REPO_ROOT}/selftests/bpf"
|
||||
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
|
||||
|
||||
tar -C "${REPO_ROOT}/selftests" -c bpf | tar_in "/${PROJECT_NAME}/selftests"
|
||||
tar -C "${REPO_ROOT}/travis-ci" -c vmtest | tar_in "/${PROJECT_NAME}/travis-ci"
|
||||
fi
|
||||
fi
|
||||
|
||||
setup_script="#!/bin/sh
|
||||
tmp=$(mktemp)
|
||||
cat <<HERE >"$tmp"
|
||||
"#!/bin/sh
|
||||
|
||||
echo 'Skipping setup commands'
|
||||
echo 0 > /exitstatus
|
||||
chmod 644 /exitstatus"
|
||||
echo vm_start:0 > /exitstatus
|
||||
chmod 644 /exitstatus
|
||||
HERE
|
||||
|
||||
# Create the init scripts.
|
||||
if [[ ! -z SETUPCMD ]]; then
|
||||
@@ -427,51 +469,101 @@ if [[ ! -z SETUPCMD ]]; then
|
||||
kernel="${KERNELRELEASE}"
|
||||
if [[ -v BUILDDIR ]]; then kernel='latest'; fi
|
||||
setup_envvars="export KERNEL=${kernel}"
|
||||
setup_script=$(printf "#!/bin/sh
|
||||
cat <<HERE >"$tmp"
|
||||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
echo 'Running setup commands'
|
||||
%s
|
||||
set +e; %s; exitstatus=\$?; set -e
|
||||
echo \$exitstatus > /exitstatus
|
||||
chmod 644 /exitstatus" "${setup_envvars}" "${setup_cmd}")
|
||||
${setup_envvars}
|
||||
set +e
|
||||
${setup_cmd}; exitstatus=\$?
|
||||
echo -e '$(travis_fold start collect_status "Collect status")'
|
||||
set -e
|
||||
# If setup command did not write its exit status to /exitstatus, do it now
|
||||
if [[ ! -s /exitstatus ]]; then
|
||||
echo setup_cmd:\$exitstatus > /exitstatus
|
||||
fi
|
||||
chmod 644 /exitstatus
|
||||
echo -e '$(travis_fold end collect_status)'
|
||||
echo -e '$(travis_fold start shutdown Shutdown)'
|
||||
HERE
|
||||
fi
|
||||
|
||||
echo "${setup_script}" | sudo tee "$mnt/etc/rcS.d/S50-run-tests" > /dev/null
|
||||
sudo chmod 755 "$mnt/etc/rcS.d/S50-run-tests"
|
||||
guestfish --remote \
|
||||
upload "$tmp" /etc/rcS.d/S50-run-tests : \
|
||||
chmod 755 /etc/rcS.d/S50-run-tests
|
||||
|
||||
fold_shutdown="$(travis_fold start shutdown)"
|
||||
poweroff_script="#!/bin/sh
|
||||
cat <<HERE >"$tmp"
|
||||
#!/bin/sh
|
||||
|
||||
echo ${fold_shutdown}
|
||||
echo -e '\033[1;33mShutdown\033[0m\n'
|
||||
poweroff
|
||||
HERE
|
||||
guestfish --remote \
|
||||
upload "$tmp" /etc/rcS.d/S99-poweroff : \
|
||||
chmod 755 /etc/rcS.d/S99-poweroff
|
||||
rm "$tmp"
|
||||
tmp=
|
||||
|
||||
poweroff"
|
||||
echo "${poweroff_script}" | sudo tee "$mnt/etc/rcS.d/S99-poweroff" > /dev/null
|
||||
sudo chmod 755 "$mnt/etc/rcS.d/S99-poweroff"
|
||||
|
||||
sudo umount "$mnt"
|
||||
guestfish --remote exit
|
||||
|
||||
echo "Starting VM with $(nproc) CPUs..."
|
||||
|
||||
case "$ARCH" in
|
||||
s390x)
|
||||
qemu="qemu-system-s390x"
|
||||
console="ttyS1"
|
||||
smp=2
|
||||
kvm_accel="-enable-kvm"
|
||||
tcg_accel="-machine accel=tcg"
|
||||
;;
|
||||
x86_64)
|
||||
qemu="qemu-system-x86_64"
|
||||
console="ttyS0,115200"
|
||||
smp=$(nproc)
|
||||
kvm_accel="-cpu kvm64 -enable-kvm"
|
||||
tcg_accel="-cpu qemu64 -machine accel=tcg"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if kvm-ok ; then
|
||||
accel="-cpu kvm64 -enable-kvm"
|
||||
accel=$kvm_accel
|
||||
else
|
||||
accel="-cpu qemu64 -machine accel=tcg"
|
||||
accel=$tcg_accel
|
||||
fi
|
||||
qemu-system-x86_64 -nodefaults -display none -serial mon:stdio -no-reboot \
|
||||
${accel} -smp "$(nproc)" -m 4G \
|
||||
"$qemu" -nodefaults -display none -serial mon:stdio \
|
||||
${accel} -smp "$smp" -m 4G \
|
||||
-drive file="$IMG",format=raw,index=1,media=disk,if=virtio,cache=none \
|
||||
-kernel "$vmlinuz" -append "root=/dev/vda rw console=ttyS0,115200 kernel.panic=-1 $APPEND"
|
||||
sudo mount -o loop "$IMG" "$mnt"
|
||||
if exitstatus="$(cat "$mnt/exitstatus" 2>/dev/null)"; then
|
||||
-kernel "$vmlinuz" -append "root=/dev/vda rw console=$console kernel.panic=-1 $APPEND"
|
||||
|
||||
# Set exit status to 1 if at least one group test returned non-0
|
||||
exitfile="${bpftool_exitstatus}${bpftool_exitstatus:+\n}"
|
||||
exitfile+="$(guestfish --ro -a "$IMG" -i cat /exitstatus 2>/dev/null)"
|
||||
exitstatus="$(echo -e "$exitfile" | awk --field-separator ':' \
|
||||
'BEGIN { s=0 } { if ($2) {s=1} } END { print s }')"
|
||||
|
||||
if [[ "$exitstatus" =~ ^[0-9]+$ ]]; then
|
||||
printf '\nTests exit status: %s\n' "$exitstatus" >&2
|
||||
else
|
||||
printf '\nCould not read tests exit status\n' >&2
|
||||
printf '\nCould not read tests exit status ("%s")\n' "$exitstatus" >&2
|
||||
exitstatus=1
|
||||
fi
|
||||
sudo umount "$mnt"
|
||||
|
||||
travis_fold end shutdown
|
||||
|
||||
# Final summary - Don't use a fold, keep it visible
|
||||
echo -e "\033[1;33mTest Results:\033[0m"
|
||||
echo -e "$exitfile" | while read result; do
|
||||
testgroup=${result%:*}
|
||||
status=${result#*:}
|
||||
# Print final result for each group of tests
|
||||
if [[ "$status" -eq 0 ]]; then
|
||||
printf "%20s: \033[1;32mPASS\033[0m\n" "$testgroup"
|
||||
else
|
||||
printf "%20s: \033[1;31mFAIL\033[0m (returned %s)\n" "$testgroup" "$status"
|
||||
fi
|
||||
done
|
||||
|
||||
exit "$exitstatus"
|
||||
|
||||
@@ -4,42 +4,52 @@ set -euo pipefail
|
||||
|
||||
source $(cd $(dirname $0) && pwd)/helpers.sh
|
||||
|
||||
STATUS_FILE=/exitstatus
|
||||
|
||||
read_lists() {
|
||||
(for path in "$@"; do
|
||||
if [[ -s "$path" ]]; then
|
||||
cat "$path"
|
||||
fi;
|
||||
done) | cut -d'#' -f1 | tr -s ' \t\n' ','
|
||||
}
|
||||
|
||||
test_progs() {
|
||||
if [[ "${KERNEL}" != '4.9.0' ]]; then
|
||||
travis_fold start test_progs "Testing test_progs"
|
||||
./test_progs ${BLACKLIST:+-d$BLACKLIST} ${WHITELIST:+-a$WHITELIST}
|
||||
# "&& true" does not change the return code (it is not executed
|
||||
# if the Python script fails), but it prevents exiting on a
|
||||
# failure due to the "set -e".
|
||||
./test_progs ${BLACKLIST:+-d$BLACKLIST} ${WHITELIST:+-a$WHITELIST} && true
|
||||
echo "test_progs:$?" >> "${STATUS_FILE}"
|
||||
travis_fold end test_progs
|
||||
fi
|
||||
|
||||
travis_fold start test_progs-no_alu32 "Testing test_progs-no_alu32"
|
||||
./test_progs-no_alu32 ${BLACKLIST:+-d$BLACKLIST} ${WHITELIST:+-a$WHITELIST}
|
||||
./test_progs-no_alu32 ${BLACKLIST:+-d$BLACKLIST} ${WHITELIST:+-a$WHITELIST} && true
|
||||
echo "test_progs-no_alu32:$?" >> "${STATUS_FILE}"
|
||||
travis_fold end test_progs-no_alu32
|
||||
}
|
||||
|
||||
test_maps() {
|
||||
travis_fold start test_maps "Testing test_maps"
|
||||
./test_maps
|
||||
./test_maps && true
|
||||
echo "test_maps:$?" >> "${STATUS_FILE}"
|
||||
travis_fold end test_maps
|
||||
}
|
||||
|
||||
test_verifier() {
|
||||
travis_fold start test_verifier "Testing test_verifier"
|
||||
./test_verifier
|
||||
./test_verifier && true
|
||||
echo "test_verifier:$?" >> "${STATUS_FILE}"
|
||||
travis_fold end test_verifier
|
||||
}
|
||||
|
||||
travis_fold end vm_init
|
||||
|
||||
configs_path='libbpf/travis-ci/vmtest/configs'
|
||||
blacklist_path="$configs_path/blacklist/BLACKLIST-${KERNEL}"
|
||||
if [[ -s "${blacklist_path}" ]]; then
|
||||
BLACKLIST=$(cat "${blacklist_path}" | cut -d'#' -f1 | tr -s '[:space:]' ',')
|
||||
fi
|
||||
|
||||
whitelist_path="$configs_path/whitelist/WHITELIST-${KERNEL}"
|
||||
if [[ -s "${whitelist_path}" ]]; then
|
||||
WHITELIST=$(cat "${whitelist_path}" | cut -d'#' -f1 | tr -s '[:space:]' ',')
|
||||
fi
|
||||
configs_path=libbpf/travis-ci/vmtest/configs
|
||||
BLACKLIST=$(read_lists "$configs_path/blacklist/BLACKLIST-${KERNEL}" "$configs_path/blacklist/BLACKLIST-${KERNEL}.${ARCH}")
|
||||
WHITELIST=$(read_lists "$configs_path/whitelist/WHITELIST-${KERNEL}" "$configs_path/whitelist/WHITELIST-${KERNEL}.${ARCH}")
|
||||
|
||||
cd libbpf/selftests/bpf
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal mai
|
||||
sudo apt-get update
|
||||
sudo apt-get install --allow-downgrades -y libc6=2.31-0ubuntu9.2
|
||||
sudo aptitude install -y g++ libelf-dev
|
||||
sudo aptitude install -y clang-14 lld-14 llvm-14
|
||||
sudo aptitude install -y clang-14 llvm-14
|
||||
|
||||
travis_fold end install_clang
|
||||
|
||||
@@ -35,11 +35,13 @@ else
|
||||
${VMTEST_ROOT}/prepare_selftests.sh
|
||||
fi
|
||||
|
||||
travis_fold start adduser_to_kvm "Add user ${USER}"
|
||||
sudo adduser "${USER}" kvm
|
||||
travis_fold stop adduser_to_kvm
|
||||
|
||||
# Escape whitespace characters.
|
||||
setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
||||
|
||||
sudo adduser "${USER}" kvm
|
||||
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
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
|
||||
|
||||
72
travis-ci/vmtest/s390x-self-hosted-builder/README.md
Normal file
72
travis-ci/vmtest/s390x-self-hosted-builder/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# IBM Z self-hosted builder
|
||||
|
||||
libbpf CI uses an IBM-provided z15 self-hosted builder. There are no IBM Z
|
||||
builds of GitHub Actions runner, and stable qemu-user has problems with .NET
|
||||
apps, so the builder runs the x86_64 runner version with qemu-user built from
|
||||
the master branch.
|
||||
|
||||
## Configuring the builder.
|
||||
|
||||
### Install prerequisites.
|
||||
|
||||
```
|
||||
$ sudo dnf install docker
|
||||
```
|
||||
|
||||
### Add services.
|
||||
|
||||
```
|
||||
$ sudo cp *.service /etc/systemd/system/
|
||||
$ sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
### Create a config file.
|
||||
|
||||
```
|
||||
$ sudo tee /etc/actions-runner-libbpf
|
||||
repo=<owner>/<name>
|
||||
access_token=<ghp_***>
|
||||
```
|
||||
|
||||
Access token should have the repo scope, consult
|
||||
https://docs.github.com/en/rest/reference/actions#create-a-registration-token-for-a-repository
|
||||
for details.
|
||||
|
||||
### Autostart the x86_64 emulation support.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now qemu-user-static
|
||||
```
|
||||
|
||||
### Autostart the runner.
|
||||
|
||||
```
|
||||
$ sudo systemctl enable --now actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Rebuilding the image
|
||||
|
||||
In order to update the `iiilinuxibmcom/actions-runner-libbpf` image, e.g. to
|
||||
get the latest OS security fixes, use the following commands:
|
||||
|
||||
```
|
||||
$ sudo docker build \
|
||||
--pull \
|
||||
-f actions-runner-libbpf.Dockerfile \
|
||||
-t iiilinuxibmcom/actions-runner-libbpf
|
||||
$ sudo systemctl restart actions-runner-libbpf
|
||||
```
|
||||
|
||||
## Removing persistent data
|
||||
|
||||
The `actions-runner-libbpf` service stores various temporary data, such as
|
||||
runner registration information, work directories and logs, in the
|
||||
`actions-runner-libbpf` volume. In order to remove it and start from scratch,
|
||||
e.g. when switching the runner to a different repository, use the following
|
||||
commands:
|
||||
|
||||
```
|
||||
$ sudo systemctl stop actions-runner-libbpf
|
||||
$ sudo docker rm -f actions-runner-libbpf
|
||||
$ sudo docker volume rm actions-runner-libbpf
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
# Self-Hosted IBM Z Github Actions Runner.
|
||||
|
||||
# Temporary image: amd64 dependencies.
|
||||
FROM amd64/ubuntu:20.04 as ld-prefix
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install ca-certificates libicu66 libssl1.1
|
||||
|
||||
# Main image.
|
||||
FROM s390x/ubuntu:20.04
|
||||
|
||||
# Packages for libbpf testing that are not installed by .github/actions/setup.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get -y install \
|
||||
bc \
|
||||
bison \
|
||||
cmake \
|
||||
cpu-checker \
|
||||
curl \
|
||||
flex \
|
||||
git \
|
||||
jq \
|
||||
linux-image-generic \
|
||||
qemu-system-s390x \
|
||||
rsync \
|
||||
software-properties-common \
|
||||
sudo \
|
||||
tree
|
||||
|
||||
# amd64 dependencies.
|
||||
COPY --from=ld-prefix / /usr/x86_64-linux-gnu/
|
||||
RUN ln -fs ../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /usr/x86_64-linux-gnu/lib64/
|
||||
RUN ln -fs /etc/resolv.conf /usr/x86_64-linux-gnu/etc/
|
||||
ENV QEMU_LD_PREFIX=/usr/x86_64-linux-gnu
|
||||
|
||||
# amd64 Github Actions Runner.
|
||||
RUN useradd -m actions-runner
|
||||
RUN echo "actions-runner ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
||||
RUN echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >>/etc/sudoers
|
||||
USER actions-runner
|
||||
ENV USER=actions-runner
|
||||
WORKDIR /home/actions-runner
|
||||
RUN curl -L https://github.com/actions/runner/releases/download/v2.283.2/actions-runner-linux-x64-2.283.2.tar.gz | tar -xz
|
||||
VOLUME /home/actions-runner
|
||||
|
||||
# Scripts.
|
||||
COPY fs/ /
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/usr/bin/actions-runner"]
|
||||
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Self-Hosted IBM Z Github Actions Runner
|
||||
Wants=qemu-user-static
|
||||
After=qemu-user-static
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/docker run \
|
||||
--device=/dev/kvm \
|
||||
--env-file=/etc/actions-runner-libbpf \
|
||||
--init \
|
||||
--interactive \
|
||||
--name=actions-runner-libbpf \
|
||||
--rm \
|
||||
--volume=actions-runner-libbpf:/home/actions-runner \
|
||||
iiilinuxibmcom/actions-runner-libbpf
|
||||
ExecStop=/bin/sh -c "docker exec actions-runner-libbpf kill -INT -- -1"
|
||||
ExecStop=/bin/sh -c "docker wait actions-runner-libbpf"
|
||||
ExecStop=/bin/sh -c "docker rm actions-runner-libbpf"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
40
travis-ci/vmtest/s390x-self-hosted-builder/fs/usr/bin/actions-runner
Executable file
40
travis-ci/vmtest/s390x-self-hosted-builder/fs/usr/bin/actions-runner
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Ephemeral runner startup script.
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
#
|
||||
# - repo=<owner>/<name>
|
||||
# - access_token=<ghp_***>
|
||||
#
|
||||
|
||||
set -e -u
|
||||
|
||||
# Check the cached registration token.
|
||||
token_file=registration-token.json
|
||||
set +e
|
||||
expires_at=$(jq --raw-output .expires_at "$token_file" 2>/dev/null)
|
||||
status=$?
|
||||
set -e
|
||||
if [[ $status -ne 0 || $(date +%s) -ge $(date -d "$expires_at" +%s) ]]; then
|
||||
# Refresh the cached registration token.
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $access_token" \
|
||||
"https://api.github.com/repos/$repo/actions/runners/registration-token" \
|
||||
-o "$token_file"
|
||||
fi
|
||||
|
||||
# (Re-)register the runner.
|
||||
registration_token=$(jq --raw-output .token "$token_file")
|
||||
./config.sh remove --token "$registration_token" || true
|
||||
./config.sh \
|
||||
--url "https://github.com/$repo" \
|
||||
--token "$registration_token" \
|
||||
--labels z15 \
|
||||
--ephemeral
|
||||
|
||||
# Run one job.
|
||||
./run.sh
|
||||
35
travis-ci/vmtest/s390x-self-hosted-builder/fs/usr/bin/entrypoint
Executable file
35
travis-ci/vmtest/s390x-self-hosted-builder/fs/usr/bin/entrypoint
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Container entrypoint that waits for all spawned processes.
|
||||
#
|
||||
|
||||
set -e -u
|
||||
|
||||
# /dev/kvm has host permissions, fix it.
|
||||
if [ -e /dev/kvm ]; then
|
||||
sudo chown root:kvm /dev/kvm
|
||||
fi
|
||||
|
||||
# Create a FIFO and start reading from its read end.
|
||||
tempdir=$(mktemp -d "/tmp/done.XXXXXXXXXX")
|
||||
trap 'rm -r "$tempdir"' EXIT
|
||||
done="$tempdir/pipe"
|
||||
mkfifo "$done"
|
||||
cat "$done" & waiter=$!
|
||||
|
||||
# Start the workload. Its descendants will inherit the FIFO's write end.
|
||||
status=0
|
||||
if [ "$#" -eq 0 ]; then
|
||||
bash 9>"$done" || status=$?
|
||||
else
|
||||
"$@" 9>"$done" || status=$?
|
||||
fi
|
||||
|
||||
# When the workload and all of its descendants exit, the FIFO's write end will
|
||||
# be closed and `cat "$done"` will exit. Wait until it happens. This is needed
|
||||
# in order to handle SelfUpdater, which the workload may start in background
|
||||
# before exiting.
|
||||
wait "$waiter"
|
||||
|
||||
exit "$status"
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Support for transparent execution of non-native binaries with QEMU user emulation
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# The source code for iiilinuxibmcom/qemu-user-static is at https://github.com/iii-i/qemu-user-static/tree/v6.1.0-1
|
||||
# TODO: replace it with multiarch/qemu-user-static once version >6.1 is available
|
||||
ExecStart=/usr/bin/docker run --rm --interactive --privileged iiilinuxibmcom/qemu-user-static --reset -p yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user