mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-18 15:29:06 +08:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a1615c263 | ||
|
|
e66d297441 | ||
|
|
632afdff45 | ||
|
|
6e706b38bd | ||
|
|
850293ba1c | ||
|
|
fb528063b2 | ||
|
|
97ada10bd8 | ||
|
|
9a35753b42 | ||
|
|
c4af2093cc | ||
|
|
1543a19f36 | ||
|
|
8b41602694 | ||
|
|
cecb299ac4 | ||
|
|
90e89264b9 | ||
|
|
f69cc97272 | ||
|
|
a6e9750c8a | ||
|
|
60bade6674 | ||
|
|
e13c1b7b85 | ||
|
|
1d8451ccaf | ||
|
|
fad6e249ea | ||
|
|
64f7fa917c | ||
|
|
240b8fa098 | ||
|
|
3756d20499 | ||
|
|
9e8b23289f | ||
|
|
902eca48e5 | ||
|
|
9f0d55c24a | ||
|
|
e53dd1c436 | ||
|
|
da790d6014 | ||
|
|
3d81b13b36 | ||
|
|
64bd9e074b | ||
|
|
53d473dd8e | ||
|
|
6d64d927a2 | ||
|
|
cd87f1568e | ||
|
|
c417a4cb6f | ||
|
|
fa21d33fff | ||
|
|
84cf76de9c | ||
|
|
2ef4fdac6c | ||
|
|
1d72c9c382 | ||
|
|
7930230b43 | ||
|
|
483a8c238f | ||
|
|
26cbe2384c | ||
|
|
cb4a430c8a | ||
|
|
f67d535cdb | ||
|
|
ef4785f065 | ||
|
|
9a424bea42 | ||
|
|
10e4311ad7 | ||
|
|
50febacba1 | ||
|
|
ef7d57fcec | ||
|
|
7e7a15321e | ||
|
|
77ac09c3eb | ||
|
|
40a08ef216 | ||
|
|
b6683d1aeb | ||
|
|
5247b0b0dc | ||
|
|
c2b01ad4f3 | ||
|
|
c4468dec74 | ||
|
|
40229b3ffd | ||
|
|
7f2d538c27 | ||
|
|
b7c162a433 | ||
|
|
36c26f12f1 | ||
|
|
22d5d40493 | ||
|
|
17c26b7da6 | ||
|
|
e287979374 | ||
|
|
552af3d963 | ||
|
|
c772c9cbde | ||
|
|
031a38cceb | ||
|
|
6ff5062480 | ||
|
|
fdff85e63e | ||
|
|
5c7661fd5e | ||
|
|
1feb21b081 | ||
|
|
fa8cb316fb | ||
|
|
f72fe00e70 |
181
.travis.yml
181
.travis.yml
@@ -8,17 +8,9 @@ env:
|
||||
global:
|
||||
- PROJECT_NAME='libbpf'
|
||||
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
|
||||
- CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
|
||||
- VMTEST_ROOT="$TRAVIS_BUILD_DIR/travis-ci/vmtest"
|
||||
- REPO_ROOT="$TRAVIS_BUILD_DIR"
|
||||
- GIT_FETCH_DEPTH=64
|
||||
- VMTEST_SETUPCMD="PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
|
||||
jobs:
|
||||
# Setup command override.
|
||||
# 5.5.0-rc6 is built from bpf-next; TODO(hex@): remove when pahole v1.16 is available
|
||||
- KERNEL=5.5.0-rc6
|
||||
- KERNEL=5.5.0
|
||||
- KERNEL=LATEST
|
||||
- CI_ROOT="$REPO_ROOT/travis-ci"
|
||||
- VMTEST_ROOT="$CI_ROOT/vmtest"
|
||||
|
||||
addons:
|
||||
apt:
|
||||
@@ -29,26 +21,7 @@ addons:
|
||||
- elfutils
|
||||
- libcap-dev
|
||||
- libelf-dev
|
||||
install: sudo adduser "${USER}" kvm
|
||||
before_script:
|
||||
- wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main" | sudo tee -a /etc/apt/sources.list
|
||||
- echo "deb http://archive.ubuntu.com/ubuntu eoan main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get -y install dwarves=1.15-1
|
||||
- sudo apt-get -qq -y install clang-10 lld-10 llvm-10
|
||||
- if [[ "${KERNEL}" = 'LATEST' ]]; then ${VMTEST_ROOT}/build_latest_kernel.sh travis-ci/vmtest/bpf-next; fi
|
||||
- ${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
|
||||
# Escape whitespace characters.
|
||||
- setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
||||
- if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||
else
|
||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||
fi; exitstatus=$?
|
||||
- test $exitstatus -le 1
|
||||
script:
|
||||
- test $exitstatus -eq 0
|
||||
- libdw-dev
|
||||
|
||||
stages:
|
||||
# Run Coverity periodically instead of for each PR for following reasons:
|
||||
@@ -62,130 +35,72 @@ stages:
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: Build & test
|
||||
name: Debian Testing
|
||||
- stage: Build
|
||||
name: Debian Build
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
# Override before_script: so VMTEST before_install commands are not executed.
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Testing (ASan+UBSan)
|
||||
- name: Debian Build (ASan+UBSan)
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN_ASAN || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_ASAN || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Testing (clang)
|
||||
- name: Debian Build (clang)
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN_CLANG || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_CLANG || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Testing (clang ASan+UBSan)
|
||||
- name: Debian Build (clang ASan+UBSan)
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN_CLANG_ASAN || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_CLANG_ASAN || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Testing (gcc-8)
|
||||
- name: Debian Build (gcc-8)
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN_GCC8 || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8 || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Debian Testing (gcc-8 ASan+UBSan)
|
||||
- name: Debian Build (gcc-8 ASan+UBSan)
|
||||
language: bash
|
||||
env:
|
||||
- DEBIAN_RELEASE="testing"
|
||||
- CONT_NAME="libbpf-debian-$DEBIAN_RELEASE"
|
||||
before_install:
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- docker --version
|
||||
install:
|
||||
- $CI_MANAGERS/debian.sh SETUP
|
||||
before_script: true
|
||||
script:
|
||||
- $CI_MANAGERS/debian.sh RUN_GCC8_ASAN || travis_terminate
|
||||
after_script:
|
||||
- $CI_MANAGERS/debian.sh CLEANUP
|
||||
install: $CI_ROOT/managers/debian.sh SETUP
|
||||
script: $CI_ROOT/managers/debian.sh RUN_GCC8_ASAN || travis_terminate
|
||||
after_script: $CI_ROOT/managers/debian.sh CLEANUP
|
||||
|
||||
- name: Ubuntu Bionic
|
||||
- name: Ubuntu Bionic Build
|
||||
language: bash
|
||||
before_script: true
|
||||
script:
|
||||
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate
|
||||
|
||||
- name: Ubuntu Bionic (arm)
|
||||
- name: Ubuntu Bionic Build (arm)
|
||||
arch: arm64
|
||||
language: bash
|
||||
before_script: true
|
||||
script:
|
||||
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate
|
||||
|
||||
- name: Ubuntu Bionic (s390x)
|
||||
- name: Ubuntu Bionic Build (s390x)
|
||||
arch: s390x
|
||||
language: bash
|
||||
before_script: true
|
||||
script:
|
||||
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate
|
||||
|
||||
- name: Ubuntu Bionic (ppc64le)
|
||||
- name: Ubuntu Bionic Build (ppc64le)
|
||||
arch: ppc64le
|
||||
language: bash
|
||||
before_script: true
|
||||
script:
|
||||
- sudo $CI_MANAGERS/ubuntu.sh || travis_terminate
|
||||
script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate
|
||||
|
||||
- stage: Build & Test
|
||||
name: Kernel 5.5.0 + selftests
|
||||
language: bash
|
||||
env: KERNEL=5.5.0
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate
|
||||
|
||||
- name: Kernel LATEST + selftests
|
||||
language: bash
|
||||
env: KERNEL=LATEST
|
||||
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate
|
||||
|
||||
- stage: Coverity
|
||||
language: bash
|
||||
@@ -205,7 +120,5 @@ jobs:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y build-dep libelf-dev
|
||||
- sudo apt-get install -y libelf-dev pkg-config
|
||||
# Override before_script: so VMTEST before_script commands are not executed.
|
||||
before_script: true
|
||||
script:
|
||||
- scripts/coverity.sh || travis_terminate
|
||||
|
||||
@@ -1 +1 @@
|
||||
08dc225d8868d5094ada62f471ebdfcce9dbc298
|
||||
edadedf1c5b4e4404192a0a4c3c0c05e3b7672ab
|
||||
|
||||
@@ -1 +1 @@
|
||||
35b9211c0a2427e8f39e534f442f43804fc8d5ca
|
||||
2fcd80144b93ff90836a44f2054b4d82133d3a85
|
||||
|
||||
@@ -73,7 +73,7 @@ struct bpf_insn {
|
||||
/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
|
||||
struct bpf_lpm_trie_key {
|
||||
__u32 prefixlen; /* up to 32 for AF_INET, 128 for AF_INET6 */
|
||||
__u8 data[0]; /* Arbitrary size */
|
||||
__u8 data[]; /* Arbitrary size */
|
||||
};
|
||||
|
||||
struct bpf_cgroup_storage_key {
|
||||
@@ -111,6 +111,8 @@ enum bpf_cmd {
|
||||
BPF_MAP_LOOKUP_AND_DELETE_BATCH,
|
||||
BPF_MAP_UPDATE_BATCH,
|
||||
BPF_MAP_DELETE_BATCH,
|
||||
BPF_LINK_CREATE,
|
||||
BPF_LINK_UPDATE,
|
||||
};
|
||||
|
||||
enum bpf_map_type {
|
||||
@@ -181,6 +183,7 @@ enum bpf_prog_type {
|
||||
BPF_PROG_TYPE_TRACING,
|
||||
BPF_PROG_TYPE_STRUCT_OPS,
|
||||
BPF_PROG_TYPE_EXT,
|
||||
BPF_PROG_TYPE_LSM,
|
||||
};
|
||||
|
||||
enum bpf_attach_type {
|
||||
@@ -210,6 +213,8 @@ enum bpf_attach_type {
|
||||
BPF_TRACE_RAW_TP,
|
||||
BPF_TRACE_FENTRY,
|
||||
BPF_TRACE_FEXIT,
|
||||
BPF_MODIFY_RETURN,
|
||||
BPF_LSM_MAC,
|
||||
__MAX_BPF_ATTACH_TYPE
|
||||
};
|
||||
|
||||
@@ -325,44 +330,46 @@ enum bpf_attach_type {
|
||||
#define BPF_PSEUDO_CALL 1
|
||||
|
||||
/* flags for BPF_MAP_UPDATE_ELEM command */
|
||||
#define BPF_ANY 0 /* create new element or update existing */
|
||||
#define BPF_NOEXIST 1 /* create new element if it didn't exist */
|
||||
#define BPF_EXIST 2 /* update existing element */
|
||||
#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */
|
||||
enum {
|
||||
BPF_ANY = 0, /* create new element or update existing */
|
||||
BPF_NOEXIST = 1, /* create new element if it didn't exist */
|
||||
BPF_EXIST = 2, /* update existing element */
|
||||
BPF_F_LOCK = 4, /* spin_lock-ed map_lookup/map_update */
|
||||
};
|
||||
|
||||
/* flags for BPF_MAP_CREATE command */
|
||||
#define BPF_F_NO_PREALLOC (1U << 0)
|
||||
enum {
|
||||
BPF_F_NO_PREALLOC = (1U << 0),
|
||||
/* Instead of having one common LRU list in the
|
||||
* BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list
|
||||
* which can scale and perform better.
|
||||
* Note, the LRU nodes (including free nodes) cannot be moved
|
||||
* across different LRU lists.
|
||||
*/
|
||||
#define BPF_F_NO_COMMON_LRU (1U << 1)
|
||||
BPF_F_NO_COMMON_LRU = (1U << 1),
|
||||
/* Specify numa node during map creation */
|
||||
#define BPF_F_NUMA_NODE (1U << 2)
|
||||
|
||||
#define BPF_OBJ_NAME_LEN 16U
|
||||
BPF_F_NUMA_NODE = (1U << 2),
|
||||
|
||||
/* Flags for accessing BPF object from syscall side. */
|
||||
#define BPF_F_RDONLY (1U << 3)
|
||||
#define BPF_F_WRONLY (1U << 4)
|
||||
BPF_F_RDONLY = (1U << 3),
|
||||
BPF_F_WRONLY = (1U << 4),
|
||||
|
||||
/* Flag for stack_map, store build_id+offset instead of pointer */
|
||||
#define BPF_F_STACK_BUILD_ID (1U << 5)
|
||||
BPF_F_STACK_BUILD_ID = (1U << 5),
|
||||
|
||||
/* Zero-initialize hash function seed. This should only be used for testing. */
|
||||
#define BPF_F_ZERO_SEED (1U << 6)
|
||||
BPF_F_ZERO_SEED = (1U << 6),
|
||||
|
||||
/* Flags for accessing BPF object from program side. */
|
||||
#define BPF_F_RDONLY_PROG (1U << 7)
|
||||
#define BPF_F_WRONLY_PROG (1U << 8)
|
||||
BPF_F_RDONLY_PROG = (1U << 7),
|
||||
BPF_F_WRONLY_PROG = (1U << 8),
|
||||
|
||||
/* Clone map from listener for newly accepted socket */
|
||||
#define BPF_F_CLONE (1U << 9)
|
||||
BPF_F_CLONE = (1U << 9),
|
||||
|
||||
/* Enable memory-mapping BPF map */
|
||||
#define BPF_F_MMAPABLE (1U << 10)
|
||||
BPF_F_MMAPABLE = (1U << 10),
|
||||
};
|
||||
|
||||
/* Flags for BPF_PROG_QUERY. */
|
||||
|
||||
@@ -391,6 +398,8 @@ struct bpf_stack_build_id {
|
||||
};
|
||||
};
|
||||
|
||||
#define BPF_OBJ_NAME_LEN 16U
|
||||
|
||||
union bpf_attr {
|
||||
struct { /* anonymous struct used by BPF_MAP_CREATE command */
|
||||
__u32 map_type; /* one of enum bpf_map_type */
|
||||
@@ -534,7 +543,7 @@ union bpf_attr {
|
||||
__u32 prog_cnt;
|
||||
} query;
|
||||
|
||||
struct {
|
||||
struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */
|
||||
__u64 name;
|
||||
__u32 prog_fd;
|
||||
} raw_tracepoint;
|
||||
@@ -562,6 +571,24 @@ union bpf_attr {
|
||||
__u64 probe_offset; /* output: probe_offset */
|
||||
__u64 probe_addr; /* output: probe_addr */
|
||||
} task_fd_query;
|
||||
|
||||
struct { /* struct used by BPF_LINK_CREATE command */
|
||||
__u32 prog_fd; /* eBPF program to attach */
|
||||
__u32 target_fd; /* object to attach to */
|
||||
__u32 attach_type; /* attach type */
|
||||
__u32 flags; /* extra flags */
|
||||
} link_create;
|
||||
|
||||
struct { /* struct used by BPF_LINK_UPDATE command */
|
||||
__u32 link_fd; /* link fd */
|
||||
/* new program fd to update link with */
|
||||
__u32 new_prog_fd;
|
||||
__u32 flags; /* extra flags */
|
||||
/* expected link's program fd; is specified only if
|
||||
* BPF_F_REPLACE flag is set in flags */
|
||||
__u32 old_prog_fd;
|
||||
} link_update;
|
||||
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/* The description below is an attempt at providing documentation to eBPF
|
||||
@@ -1045,9 +1072,9 @@ union bpf_attr {
|
||||
* supports redirection to the egress interface, and accepts no
|
||||
* flag at all.
|
||||
*
|
||||
* The same effect can be attained with the more generic
|
||||
* **bpf_redirect_map**\ (), which requires specific maps to be
|
||||
* used but offers better performance.
|
||||
* The same effect can also be attained with the more generic
|
||||
* **bpf_redirect_map**\ (), which uses a BPF map to store the
|
||||
* redirect target instead of providing it directly to the helper.
|
||||
* Return
|
||||
* For XDP, the helper returns **XDP_REDIRECT** on success or
|
||||
* **XDP_ABORTED** on error. For other program types, the values
|
||||
@@ -1611,13 +1638,11 @@ union bpf_attr {
|
||||
* the caller. Any higher bits in the *flags* argument must be
|
||||
* unset.
|
||||
*
|
||||
* When used to redirect packets to net devices, this helper
|
||||
* provides a high performance increase over **bpf_redirect**\ ().
|
||||
* This is due to various implementation details of the underlying
|
||||
* mechanisms, one of which is the fact that **bpf_redirect_map**\
|
||||
* () tries to send packet as a "bulk" to the device.
|
||||
* See also bpf_redirect(), which only supports redirecting to an
|
||||
* ifindex, but doesn't require a map to do so.
|
||||
* Return
|
||||
* **XDP_REDIRECT** on success, or **XDP_ABORTED** on error.
|
||||
* **XDP_REDIRECT** on success, or the value of the two lower bits
|
||||
* of the **flags* argument on error.
|
||||
*
|
||||
* int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags)
|
||||
* Description
|
||||
@@ -2892,6 +2917,114 @@ union bpf_attr {
|
||||
* Obtain the 64bit jiffies
|
||||
* Return
|
||||
* The 64 bit jiffies
|
||||
*
|
||||
* int bpf_read_branch_records(struct bpf_perf_event_data *ctx, void *buf, u32 size, u64 flags)
|
||||
* Description
|
||||
* For an eBPF program attached to a perf event, retrieve the
|
||||
* branch records (struct perf_branch_entry) associated to *ctx*
|
||||
* and store it in the buffer pointed by *buf* up to size
|
||||
* *size* bytes.
|
||||
* Return
|
||||
* On success, number of bytes written to *buf*. On error, a
|
||||
* negative value.
|
||||
*
|
||||
* The *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to
|
||||
* instead return the number of bytes required to store all the
|
||||
* branch entries. If this flag is set, *buf* may be NULL.
|
||||
*
|
||||
* **-EINVAL** if arguments invalid or **size** not a multiple
|
||||
* of sizeof(struct perf_branch_entry).
|
||||
*
|
||||
* **-ENOENT** if architecture does not support branch records.
|
||||
*
|
||||
* int bpf_get_ns_current_pid_tgid(u64 dev, u64 ino, struct bpf_pidns_info *nsdata, u32 size)
|
||||
* Description
|
||||
* Returns 0 on success, values for *pid* and *tgid* as seen from the current
|
||||
* *namespace* will be returned in *nsdata*.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EINVAL** if dev and inum supplied don't match dev_t and inode number
|
||||
* with nsfs of current task, or if dev conversion to dev_t lost high bits.
|
||||
*
|
||||
* **-ENOENT** if pidns does not exists for the current task.
|
||||
*
|
||||
* int bpf_xdp_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
||||
* Description
|
||||
* Write raw *data* blob into a special BPF perf event held by
|
||||
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
||||
* event must have the following attributes: **PERF_SAMPLE_RAW**
|
||||
* as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and
|
||||
* **PERF_COUNT_SW_BPF_OUTPUT** as **config**.
|
||||
*
|
||||
* The *flags* are used to indicate the index in *map* for which
|
||||
* the value must be put, masked with **BPF_F_INDEX_MASK**.
|
||||
* Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU**
|
||||
* to indicate that the index of the current CPU core should be
|
||||
* used.
|
||||
*
|
||||
* The value to write, of *size*, is passed through eBPF stack and
|
||||
* pointed by *data*.
|
||||
*
|
||||
* *ctx* is a pointer to in-kernel struct xdp_buff.
|
||||
*
|
||||
* This helper is similar to **bpf_perf_eventoutput**\ () but
|
||||
* restricted to raw_tracepoint bpf programs.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* u64 bpf_get_netns_cookie(void *ctx)
|
||||
* Description
|
||||
* Retrieve the cookie (generated by the kernel) of the network
|
||||
* namespace the input *ctx* is associated with. The network
|
||||
* namespace cookie remains stable for its lifetime and provides
|
||||
* a global identifier that can be assumed unique. If *ctx* is
|
||||
* NULL, then the helper returns the cookie for the initial
|
||||
* network namespace. The cookie itself is very similar to that
|
||||
* of bpf_get_socket_cookie() helper, but for network namespaces
|
||||
* instead of sockets.
|
||||
* Return
|
||||
* A 8-byte long opaque number.
|
||||
*
|
||||
* u64 bpf_get_current_ancestor_cgroup_id(int ancestor_level)
|
||||
* Description
|
||||
* Return id of cgroup v2 that is ancestor of the cgroup associated
|
||||
* with the current task at the *ancestor_level*. The root cgroup
|
||||
* is at *ancestor_level* zero and each step down the hierarchy
|
||||
* increments the level. If *ancestor_level* == level of cgroup
|
||||
* associated with the current task, then return value will be the
|
||||
* same as that of **bpf_get_current_cgroup_id**\ ().
|
||||
*
|
||||
* The helper is useful to implement policies based on cgroups
|
||||
* that are upper in hierarchy than immediate cgroup associated
|
||||
* with the current task.
|
||||
*
|
||||
* The format of returned id and helper limitations are same as in
|
||||
* **bpf_get_current_cgroup_id**\ ().
|
||||
* Return
|
||||
* The id is returned or 0 in case the id could not be retrieved.
|
||||
*
|
||||
* int bpf_sk_assign(struct sk_buff *skb, struct bpf_sock *sk, u64 flags)
|
||||
* Description
|
||||
* Assign the *sk* to the *skb*. When combined with appropriate
|
||||
* routing configuration to receive the packet towards the socket,
|
||||
* will cause *skb* to be delivered to the specified socket.
|
||||
* Subsequent redirection of *skb* via **bpf_redirect**\ (),
|
||||
* **bpf_clone_redirect**\ () or other methods outside of BPF may
|
||||
* interfere with successful delivery to the socket.
|
||||
*
|
||||
* This operation is only valid from TC ingress path.
|
||||
*
|
||||
* The *flags* argument must be zero.
|
||||
* Return
|
||||
* 0 on success, or a negative errno in case of failure.
|
||||
*
|
||||
* * **-EINVAL** Unsupported flags specified.
|
||||
* * **-ENOENT** Socket is unavailable for assignment.
|
||||
* * **-ENETUNREACH** Socket is unreachable (wrong netns).
|
||||
* * **-EOPNOTSUPP** Unsupported operation, for example a
|
||||
* call from outside of TC ingress.
|
||||
* * **-ESOCKTNOSUPPORT** Socket type not supported (reuseport).
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -3012,7 +3145,13 @@ union bpf_attr {
|
||||
FN(probe_read_kernel_str), \
|
||||
FN(tcp_send_ack), \
|
||||
FN(send_signal_thread), \
|
||||
FN(jiffies64),
|
||||
FN(jiffies64), \
|
||||
FN(read_branch_records), \
|
||||
FN(get_ns_current_pid_tgid), \
|
||||
FN(xdp_output), \
|
||||
FN(get_netns_cookie), \
|
||||
FN(get_current_ancestor_cgroup_id), \
|
||||
FN(sk_assign),
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
* function eBPF program intends to call
|
||||
@@ -3027,69 +3166,100 @@ enum bpf_func_id {
|
||||
/* All flags used by eBPF helper functions, placed here. */
|
||||
|
||||
/* BPF_FUNC_skb_store_bytes flags. */
|
||||
#define BPF_F_RECOMPUTE_CSUM (1ULL << 0)
|
||||
#define BPF_F_INVALIDATE_HASH (1ULL << 1)
|
||||
enum {
|
||||
BPF_F_RECOMPUTE_CSUM = (1ULL << 0),
|
||||
BPF_F_INVALIDATE_HASH = (1ULL << 1),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags.
|
||||
* First 4 bits are for passing the header field size.
|
||||
*/
|
||||
#define BPF_F_HDR_FIELD_MASK 0xfULL
|
||||
enum {
|
||||
BPF_F_HDR_FIELD_MASK = 0xfULL,
|
||||
};
|
||||
|
||||
/* BPF_FUNC_l4_csum_replace flags. */
|
||||
#define BPF_F_PSEUDO_HDR (1ULL << 4)
|
||||
#define BPF_F_MARK_MANGLED_0 (1ULL << 5)
|
||||
#define BPF_F_MARK_ENFORCE (1ULL << 6)
|
||||
enum {
|
||||
BPF_F_PSEUDO_HDR = (1ULL << 4),
|
||||
BPF_F_MARK_MANGLED_0 = (1ULL << 5),
|
||||
BPF_F_MARK_ENFORCE = (1ULL << 6),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
|
||||
#define BPF_F_INGRESS (1ULL << 0)
|
||||
enum {
|
||||
BPF_F_INGRESS = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
|
||||
#define BPF_F_TUNINFO_IPV6 (1ULL << 0)
|
||||
enum {
|
||||
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* flags for both BPF_FUNC_get_stackid and BPF_FUNC_get_stack. */
|
||||
#define BPF_F_SKIP_FIELD_MASK 0xffULL
|
||||
#define BPF_F_USER_STACK (1ULL << 8)
|
||||
enum {
|
||||
BPF_F_SKIP_FIELD_MASK = 0xffULL,
|
||||
BPF_F_USER_STACK = (1ULL << 8),
|
||||
/* flags used by BPF_FUNC_get_stackid only. */
|
||||
#define BPF_F_FAST_STACK_CMP (1ULL << 9)
|
||||
#define BPF_F_REUSE_STACKID (1ULL << 10)
|
||||
BPF_F_FAST_STACK_CMP = (1ULL << 9),
|
||||
BPF_F_REUSE_STACKID = (1ULL << 10),
|
||||
/* flags used by BPF_FUNC_get_stack only. */
|
||||
#define BPF_F_USER_BUILD_ID (1ULL << 11)
|
||||
BPF_F_USER_BUILD_ID = (1ULL << 11),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_skb_set_tunnel_key flags. */
|
||||
#define BPF_F_ZERO_CSUM_TX (1ULL << 1)
|
||||
#define BPF_F_DONT_FRAGMENT (1ULL << 2)
|
||||
#define BPF_F_SEQ_NUMBER (1ULL << 3)
|
||||
enum {
|
||||
BPF_F_ZERO_CSUM_TX = (1ULL << 1),
|
||||
BPF_F_DONT_FRAGMENT = (1ULL << 2),
|
||||
BPF_F_SEQ_NUMBER = (1ULL << 3),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
|
||||
* BPF_FUNC_perf_event_read_value flags.
|
||||
*/
|
||||
#define BPF_F_INDEX_MASK 0xffffffffULL
|
||||
#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK
|
||||
enum {
|
||||
BPF_F_INDEX_MASK = 0xffffffffULL,
|
||||
BPF_F_CURRENT_CPU = BPF_F_INDEX_MASK,
|
||||
/* BPF_FUNC_perf_event_output for sk_buff input context. */
|
||||
#define BPF_F_CTXLEN_MASK (0xfffffULL << 32)
|
||||
BPF_F_CTXLEN_MASK = (0xfffffULL << 32),
|
||||
};
|
||||
|
||||
/* Current network namespace */
|
||||
#define BPF_F_CURRENT_NETNS (-1L)
|
||||
enum {
|
||||
BPF_F_CURRENT_NETNS = (-1L),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_skb_adjust_room flags. */
|
||||
#define BPF_F_ADJ_ROOM_FIXED_GSO (1ULL << 0)
|
||||
enum {
|
||||
BPF_F_ADJ_ROOM_FIXED_GSO = (1ULL << 0),
|
||||
BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = (1ULL << 1),
|
||||
BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = (1ULL << 2),
|
||||
BPF_F_ADJ_ROOM_ENCAP_L4_GRE = (1ULL << 3),
|
||||
BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL << 4),
|
||||
};
|
||||
|
||||
#define BPF_ADJ_ROOM_ENCAP_L2_MASK 0xff
|
||||
#define BPF_ADJ_ROOM_ENCAP_L2_SHIFT 56
|
||||
enum {
|
||||
BPF_ADJ_ROOM_ENCAP_L2_MASK = 0xff,
|
||||
BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56,
|
||||
};
|
||||
|
||||
#define BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 (1ULL << 1)
|
||||
#define BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 (1ULL << 2)
|
||||
#define BPF_F_ADJ_ROOM_ENCAP_L4_GRE (1ULL << 3)
|
||||
#define BPF_F_ADJ_ROOM_ENCAP_L4_UDP (1ULL << 4)
|
||||
#define BPF_F_ADJ_ROOM_ENCAP_L2(len) (((__u64)len & \
|
||||
BPF_ADJ_ROOM_ENCAP_L2_MASK) \
|
||||
<< BPF_ADJ_ROOM_ENCAP_L2_SHIFT)
|
||||
|
||||
/* BPF_FUNC_sysctl_get_name flags. */
|
||||
#define BPF_F_SYSCTL_BASE_NAME (1ULL << 0)
|
||||
enum {
|
||||
BPF_F_SYSCTL_BASE_NAME = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_sk_storage_get flags */
|
||||
#define BPF_SK_STORAGE_GET_F_CREATE (1ULL << 0)
|
||||
enum {
|
||||
BPF_SK_STORAGE_GET_F_CREATE = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* BPF_FUNC_read_branch_records flags. */
|
||||
enum {
|
||||
BPF_F_GET_BRANCH_RECORDS_SIZE = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* Mode for BPF_FUNC_skb_adjust_room helper. */
|
||||
enum bpf_adj_room_mode {
|
||||
@@ -3155,6 +3325,7 @@ struct __sk_buff {
|
||||
__u32 wire_len;
|
||||
__u32 gso_segs;
|
||||
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||
__u32 gso_size;
|
||||
};
|
||||
|
||||
struct bpf_tunnel_key {
|
||||
@@ -3507,13 +3678,14 @@ struct bpf_sock_ops {
|
||||
};
|
||||
|
||||
/* Definitions for bpf_sock_ops_cb_flags */
|
||||
#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0)
|
||||
#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1)
|
||||
#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2)
|
||||
#define BPF_SOCK_OPS_RTT_CB_FLAG (1<<3)
|
||||
#define BPF_SOCK_OPS_ALL_CB_FLAGS 0xF /* Mask of all currently
|
||||
* supported cb flags
|
||||
*/
|
||||
enum {
|
||||
BPF_SOCK_OPS_RTO_CB_FLAG = (1<<0),
|
||||
BPF_SOCK_OPS_RETRANS_CB_FLAG = (1<<1),
|
||||
BPF_SOCK_OPS_STATE_CB_FLAG = (1<<2),
|
||||
BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3),
|
||||
/* Mask of all currently supported cb flags */
|
||||
BPF_SOCK_OPS_ALL_CB_FLAGS = 0xF,
|
||||
};
|
||||
|
||||
/* List of known BPF sock_ops operators.
|
||||
* New entries can only be added at the end
|
||||
@@ -3592,8 +3764,10 @@ enum {
|
||||
BPF_TCP_MAX_STATES /* Leave at the end! */
|
||||
};
|
||||
|
||||
#define TCP_BPF_IW 1001 /* Set TCP initial congestion window */
|
||||
#define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */
|
||||
enum {
|
||||
TCP_BPF_IW = 1001, /* Set TCP initial congestion window */
|
||||
TCP_BPF_SNDCWND_CLAMP = 1002, /* Set sndcwnd_clamp */
|
||||
};
|
||||
|
||||
struct bpf_perf_event_value {
|
||||
__u64 counter;
|
||||
@@ -3601,12 +3775,16 @@ struct bpf_perf_event_value {
|
||||
__u64 running;
|
||||
};
|
||||
|
||||
#define BPF_DEVCG_ACC_MKNOD (1ULL << 0)
|
||||
#define BPF_DEVCG_ACC_READ (1ULL << 1)
|
||||
#define BPF_DEVCG_ACC_WRITE (1ULL << 2)
|
||||
enum {
|
||||
BPF_DEVCG_ACC_MKNOD = (1ULL << 0),
|
||||
BPF_DEVCG_ACC_READ = (1ULL << 1),
|
||||
BPF_DEVCG_ACC_WRITE = (1ULL << 2),
|
||||
};
|
||||
|
||||
#define BPF_DEVCG_DEV_BLOCK (1ULL << 0)
|
||||
#define BPF_DEVCG_DEV_CHAR (1ULL << 1)
|
||||
enum {
|
||||
BPF_DEVCG_DEV_BLOCK = (1ULL << 0),
|
||||
BPF_DEVCG_DEV_CHAR = (1ULL << 1),
|
||||
};
|
||||
|
||||
struct bpf_cgroup_dev_ctx {
|
||||
/* access_type encoded as (BPF_DEVCG_ACC_* << 16) | BPF_DEVCG_DEV_* */
|
||||
@@ -3622,8 +3800,10 @@ struct bpf_raw_tracepoint_args {
|
||||
/* DIRECT: Skip the FIB rules and go to FIB table associated with device
|
||||
* OUTPUT: Do lookup from egress perspective; default is ingress
|
||||
*/
|
||||
#define BPF_FIB_LOOKUP_DIRECT (1U << 0)
|
||||
#define BPF_FIB_LOOKUP_OUTPUT (1U << 1)
|
||||
enum {
|
||||
BPF_FIB_LOOKUP_DIRECT = (1U << 0),
|
||||
BPF_FIB_LOOKUP_OUTPUT = (1U << 1),
|
||||
};
|
||||
|
||||
enum {
|
||||
BPF_FIB_LKUP_RET_SUCCESS, /* lookup successful */
|
||||
@@ -3695,9 +3875,11 @@ enum bpf_task_fd_type {
|
||||
BPF_FD_TYPE_URETPROBE, /* filename + offset */
|
||||
};
|
||||
|
||||
#define BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG (1U << 0)
|
||||
#define BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL (1U << 1)
|
||||
#define BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP (1U << 2)
|
||||
enum {
|
||||
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = (1U << 0),
|
||||
BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = (1U << 1),
|
||||
BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = (1U << 2),
|
||||
};
|
||||
|
||||
struct bpf_flow_keys {
|
||||
__u16 nhoff;
|
||||
@@ -3763,4 +3945,8 @@ struct bpf_sockopt {
|
||||
__s32 retval;
|
||||
};
|
||||
|
||||
struct bpf_pidns_info {
|
||||
__u32 pid;
|
||||
__u32 tgid;
|
||||
};
|
||||
#endif /* _UAPI__LINUX_BPF_H__ */
|
||||
|
||||
@@ -463,6 +463,7 @@ enum {
|
||||
IFLA_MACSEC_REPLAY_PROTECT,
|
||||
IFLA_MACSEC_VALIDATION,
|
||||
IFLA_MACSEC_PAD,
|
||||
IFLA_MACSEC_OFFLOAD,
|
||||
__IFLA_MACSEC_MAX,
|
||||
};
|
||||
|
||||
@@ -489,6 +490,7 @@ enum macsec_validation_type {
|
||||
enum macsec_offload {
|
||||
MACSEC_OFFLOAD_OFF = 0,
|
||||
MACSEC_OFFLOAD_PHY = 1,
|
||||
MACSEC_OFFLOAD_MAC = 2,
|
||||
__MACSEC_OFFLOAD_END,
|
||||
MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1,
|
||||
};
|
||||
@@ -960,11 +962,12 @@ enum {
|
||||
#define XDP_FLAGS_SKB_MODE (1U << 1)
|
||||
#define XDP_FLAGS_DRV_MODE (1U << 2)
|
||||
#define XDP_FLAGS_HW_MODE (1U << 3)
|
||||
#define XDP_FLAGS_REPLACE (1U << 4)
|
||||
#define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \
|
||||
XDP_FLAGS_DRV_MODE | \
|
||||
XDP_FLAGS_HW_MODE)
|
||||
#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \
|
||||
XDP_FLAGS_MODES)
|
||||
XDP_FLAGS_MODES | XDP_FLAGS_REPLACE)
|
||||
|
||||
/* These are stored into IFLA_XDP_ATTACHED on dump. */
|
||||
enum {
|
||||
@@ -984,6 +987,7 @@ enum {
|
||||
IFLA_XDP_DRV_PROG_ID,
|
||||
IFLA_XDP_SKB_PROG_ID,
|
||||
IFLA_XDP_HW_PROG_ID,
|
||||
IFLA_XDP_EXPECTED_FD,
|
||||
__IFLA_XDP_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ PATH_MAP=( \
|
||||
[tools/include/tools/libc_compat.h]=include/tools/libc_compat.h \
|
||||
)
|
||||
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]}"
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]} :^tools/lib/bpf/Makefile :^tools/lib/bpf/Build :^tools/lib/bpf/.gitignore"
|
||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf\.c|bpf_helper_defs\.h|\.gitignore)$'
|
||||
|
||||
@@ -79,9 +79,10 @@ commit_desc()
|
||||
# The idea is that this single-line signature is good enough to make final
|
||||
# decision about whether two commits are the same, across different repos.
|
||||
# $1 - commit ref
|
||||
# $2 - paths filter
|
||||
commit_signature()
|
||||
{
|
||||
git log -n1 --pretty='("%s")|%aI|%b' --shortstat $1 | tr '\n' '|'
|
||||
git show --pretty='("%s")|%aI|%b' --shortstat $1 -- ${2-.} | tr '\n' '|'
|
||||
}
|
||||
|
||||
# Validate there are no non-empty merges (we can't handle them)
|
||||
@@ -133,7 +134,7 @@ cherry_pick_commits()
|
||||
new_commits=$(git rev-list --no-merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||
for new_commit in ${new_commits}; do
|
||||
desc="$(commit_desc ${new_commit})"
|
||||
signature="$(commit_signature ${new_commit})"
|
||||
signature="$(commit_signature ${new_commit} "${LIBBPF_PATHS[@]}")"
|
||||
synced_cnt=$(grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | wc -l)
|
||||
manual_check=0
|
||||
if ((${synced_cnt} > 0)); then
|
||||
|
||||
37
src/bpf.c
37
src/bpf.c
@@ -235,7 +235,8 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_type = load_attr->prog_type;
|
||||
attr.expected_attach_type = load_attr->expected_attach_type;
|
||||
if (attr.prog_type == BPF_PROG_TYPE_STRUCT_OPS) {
|
||||
if (attr.prog_type == BPF_PROG_TYPE_STRUCT_OPS ||
|
||||
attr.prog_type == BPF_PROG_TYPE_LSM) {
|
||||
attr.attach_btf_id = load_attr->attach_btf_id;
|
||||
} else if (attr.prog_type == BPF_PROG_TYPE_TRACING ||
|
||||
attr.prog_type == BPF_PROG_TYPE_EXT) {
|
||||
@@ -584,6 +585,40 @@ int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type)
|
||||
return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type,
|
||||
const struct bpf_link_create_opts *opts)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_link_create_opts))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.link_create.prog_fd = prog_fd;
|
||||
attr.link_create.target_fd = target_fd;
|
||||
attr.link_create.attach_type = attach_type;
|
||||
|
||||
return sys_bpf(BPF_LINK_CREATE, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_link_update(int link_fd, int new_prog_fd,
|
||||
const struct bpf_link_update_opts *opts)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_link_update_opts))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.link_update.link_fd = link_fd;
|
||||
attr.link_update.new_prog_fd = new_prog_fd;
|
||||
attr.link_update.flags = OPTS_GET(opts, flags, 0);
|
||||
attr.link_update.old_prog_fd = OPTS_GET(opts, old_prog_fd, 0);
|
||||
|
||||
return sys_bpf(BPF_LINK_UPDATE, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags,
|
||||
__u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt)
|
||||
{
|
||||
|
||||
19
src/bpf.h
19
src/bpf.h
@@ -168,6 +168,25 @@ LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
struct bpf_link_create_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
};
|
||||
#define bpf_link_create_opts__last_field sz
|
||||
|
||||
LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
|
||||
enum bpf_attach_type attach_type,
|
||||
const struct bpf_link_create_opts *opts);
|
||||
|
||||
struct bpf_link_update_opts {
|
||||
size_t sz; /* size of this struct for forward/backward compatibility */
|
||||
__u32 flags; /* extra flags */
|
||||
__u32 old_prog_fd; /* expected old program FD */
|
||||
};
|
||||
#define bpf_link_update_opts__last_field old_prog_fd
|
||||
|
||||
LIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,
|
||||
const struct bpf_link_update_opts *opts);
|
||||
|
||||
struct bpf_prog_test_run_attr {
|
||||
int prog_fd;
|
||||
int repeat;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
struct bpf_fib_lookup;
|
||||
struct bpf_perf_event_data;
|
||||
struct bpf_perf_event_value;
|
||||
struct bpf_pidns_info;
|
||||
struct bpf_sock;
|
||||
struct bpf_sock_addr;
|
||||
struct bpf_sock_ops;
|
||||
@@ -576,9 +577,9 @@ static __u64 (*bpf_perf_event_read)(void *map, __u64 flags) = (void *) 22;
|
||||
* supports redirection to the egress interface, and accepts no
|
||||
* flag at all.
|
||||
*
|
||||
* The same effect can be attained with the more generic
|
||||
* **bpf_redirect_map**\ (), which requires specific maps to be
|
||||
* used but offers better performance.
|
||||
* The same effect can also be attained with the more generic
|
||||
* **bpf_redirect_map**\ (), which uses a BPF map to store the
|
||||
* redirect target instead of providing it directly to the helper.
|
||||
*
|
||||
* Returns
|
||||
* For XDP, the helper returns **XDP_REDIRECT** on success or
|
||||
@@ -1242,14 +1243,12 @@ static int (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32 m
|
||||
* the caller. Any higher bits in the *flags* argument must be
|
||||
* unset.
|
||||
*
|
||||
* When used to redirect packets to net devices, this helper
|
||||
* provides a high performance increase over **bpf_redirect**\ ().
|
||||
* This is due to various implementation details of the underlying
|
||||
* mechanisms, one of which is the fact that **bpf_redirect_map**\
|
||||
* () tries to send packet as a "bulk" to the device.
|
||||
* See also bpf_redirect(), which only supports redirecting to an
|
||||
* ifindex, but doesn't require a map to do so.
|
||||
*
|
||||
* Returns
|
||||
* **XDP_REDIRECT** on success, or **XDP_ABORTED** on error.
|
||||
* **XDP_REDIRECT** on success, or the value of the two lower bits
|
||||
* of the **flags* argument on error.
|
||||
*/
|
||||
static int (*bpf_redirect_map)(void *map, __u32 key, __u64 flags) = (void *) 51;
|
||||
|
||||
@@ -2796,4 +2795,136 @@ static int (*bpf_send_signal_thread)(__u32 sig) = (void *) 117;
|
||||
*/
|
||||
static __u64 (*bpf_jiffies64)(void) = (void *) 118;
|
||||
|
||||
/*
|
||||
* bpf_read_branch_records
|
||||
*
|
||||
* For an eBPF program attached to a perf event, retrieve the
|
||||
* branch records (struct perf_branch_entry) associated to *ctx*
|
||||
* and store it in the buffer pointed by *buf* up to size
|
||||
* *size* bytes.
|
||||
*
|
||||
* Returns
|
||||
* On success, number of bytes written to *buf*. On error, a
|
||||
* negative value.
|
||||
*
|
||||
* The *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to
|
||||
* instead return the number of bytes required to store all the
|
||||
* branch entries. If this flag is set, *buf* may be NULL.
|
||||
*
|
||||
* **-EINVAL** if arguments invalid or **size** not a multiple
|
||||
* of sizeof(struct perf_branch_entry).
|
||||
*
|
||||
* **-ENOENT** if architecture does not support branch records.
|
||||
*/
|
||||
static int (*bpf_read_branch_records)(struct bpf_perf_event_data *ctx, void *buf, __u32 size, __u64 flags) = (void *) 119;
|
||||
|
||||
/*
|
||||
* bpf_get_ns_current_pid_tgid
|
||||
*
|
||||
* Returns 0 on success, values for *pid* and *tgid* as seen from the current
|
||||
* *namespace* will be returned in *nsdata*.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EINVAL** if dev and inum supplied don't match dev_t and inode number
|
||||
* with nsfs of current task, or if dev conversion to dev_t lost high bits.
|
||||
*
|
||||
* **-ENOENT** if pidns does not exists for the current task.
|
||||
*
|
||||
*/
|
||||
static int (*bpf_get_ns_current_pid_tgid)(__u64 dev, __u64 ino, struct bpf_pidns_info *nsdata, __u32 size) = (void *) 120;
|
||||
|
||||
/*
|
||||
* bpf_xdp_output
|
||||
*
|
||||
* Write raw *data* blob into a special BPF perf event held by
|
||||
* *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
|
||||
* event must have the following attributes: **PERF_SAMPLE_RAW**
|
||||
* as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and
|
||||
* **PERF_COUNT_SW_BPF_OUTPUT** as **config**.
|
||||
*
|
||||
* The *flags* are used to indicate the index in *map* for which
|
||||
* the value must be put, masked with **BPF_F_INDEX_MASK**.
|
||||
* Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU**
|
||||
* to indicate that the index of the current CPU core should be
|
||||
* used.
|
||||
*
|
||||
* The value to write, of *size*, is passed through eBPF stack and
|
||||
* pointed by *data*.
|
||||
*
|
||||
* *ctx* is a pointer to in-kernel struct xdp_buff.
|
||||
*
|
||||
* This helper is similar to **bpf_perf_eventoutput**\ () but
|
||||
* restricted to raw_tracepoint bpf programs.
|
||||
*
|
||||
* Returns
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*/
|
||||
static int (*bpf_xdp_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 121;
|
||||
|
||||
/*
|
||||
* bpf_get_netns_cookie
|
||||
*
|
||||
* Retrieve the cookie (generated by the kernel) of the network
|
||||
* namespace the input *ctx* is associated with. The network
|
||||
* namespace cookie remains stable for its lifetime and provides
|
||||
* a global identifier that can be assumed unique. If *ctx* is
|
||||
* NULL, then the helper returns the cookie for the initial
|
||||
* network namespace. The cookie itself is very similar to that
|
||||
* of bpf_get_socket_cookie() helper, but for network namespaces
|
||||
* instead of sockets.
|
||||
*
|
||||
* Returns
|
||||
* A 8-byte long opaque number.
|
||||
*/
|
||||
static __u64 (*bpf_get_netns_cookie)(void *ctx) = (void *) 122;
|
||||
|
||||
/*
|
||||
* bpf_get_current_ancestor_cgroup_id
|
||||
*
|
||||
* Return id of cgroup v2 that is ancestor of the cgroup associated
|
||||
* with the current task at the *ancestor_level*. The root cgroup
|
||||
* is at *ancestor_level* zero and each step down the hierarchy
|
||||
* increments the level. If *ancestor_level* == level of cgroup
|
||||
* associated with the current task, then return value will be the
|
||||
* same as that of **bpf_get_current_cgroup_id**\ ().
|
||||
*
|
||||
* The helper is useful to implement policies based on cgroups
|
||||
* that are upper in hierarchy than immediate cgroup associated
|
||||
* with the current task.
|
||||
*
|
||||
* The format of returned id and helper limitations are same as in
|
||||
* **bpf_get_current_cgroup_id**\ ().
|
||||
*
|
||||
* Returns
|
||||
* The id is returned or 0 in case the id could not be retrieved.
|
||||
*/
|
||||
static __u64 (*bpf_get_current_ancestor_cgroup_id)(int ancestor_level) = (void *) 123;
|
||||
|
||||
/*
|
||||
* bpf_sk_assign
|
||||
*
|
||||
* Assign the *sk* to the *skb*. When combined with appropriate
|
||||
* routing configuration to receive the packet towards the socket,
|
||||
* will cause *skb* to be delivered to the specified socket.
|
||||
* Subsequent redirection of *skb* via **bpf_redirect**\ (),
|
||||
* **bpf_clone_redirect**\ () or other methods outside of BPF may
|
||||
* interfere with successful delivery to the socket.
|
||||
*
|
||||
* This operation is only valid from TC ingress path.
|
||||
*
|
||||
* The *flags* argument must be zero.
|
||||
*
|
||||
* Returns
|
||||
* 0 on success, or a negative errno in case of failure.
|
||||
*
|
||||
* * **-EINVAL** Unsupported flags specified.
|
||||
* * **-ENOENT** Socket is unavailable for assignment.
|
||||
* * **-ENETUNREACH** Socket is unreachable (wrong netns).
|
||||
* * **-EOPNOTSUPP** Unsupported operation, for example a
|
||||
* call from outside of TC ingress.
|
||||
* * **-ESOCKTNOSUPPORT** Socket type not supported (reuseport).
|
||||
*/
|
||||
static int (*bpf_sk_assign)(struct __sk_buff *skb, struct bpf_sock *sk, __u64 flags) = (void *) 124;
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
|
||||
#if defined(bpf_target_x86)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#if defined(__KERNEL__) || defined(__VMLINUX_H__)
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->di)
|
||||
#define PT_REGS_PARM2(x) ((x)->si)
|
||||
#define PT_REGS_PARM3(x) ((x)->dx)
|
||||
@@ -60,7 +61,20 @@
|
||||
#define PT_REGS_RC(x) ((x)->ax)
|
||||
#define PT_REGS_SP(x) ((x)->sp)
|
||||
#define PT_REGS_IP(x) ((x)->ip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), di)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), si)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), dx)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), cx)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), bp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), ax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), ip)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __i386__
|
||||
/* i386 kernel is built with -mregparm=3 */
|
||||
#define PT_REGS_PARM1(x) ((x)->eax)
|
||||
@@ -73,7 +87,20 @@
|
||||
#define PT_REGS_RC(x) ((x)->eax)
|
||||
#define PT_REGS_SP(x) ((x)->esp)
|
||||
#define PT_REGS_IP(x) ((x)->eip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), eax)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), edx)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), ecx)
|
||||
#define PT_REGS_PARM4_CORE(x) 0
|
||||
#define PT_REGS_PARM5_CORE(x) 0
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), esp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), ebp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), eax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), esp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), eip)
|
||||
|
||||
#else
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->rdi)
|
||||
#define PT_REGS_PARM2(x) ((x)->rsi)
|
||||
#define PT_REGS_PARM3(x) ((x)->rdx)
|
||||
@@ -84,6 +111,18 @@
|
||||
#define PT_REGS_RC(x) ((x)->rax)
|
||||
#define PT_REGS_SP(x) ((x)->rsp)
|
||||
#define PT_REGS_IP(x) ((x)->rip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), rdi)
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), rsi)
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), rdx)
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), rcx)
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), rsp)
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), rbp)
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), rax)
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), rsp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), rip)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -104,6 +143,17 @@ struct pt_regs;
|
||||
#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15])
|
||||
#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[3])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[4])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[5])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[6])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), grps[14])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[11])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[15])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), pdw.addr)
|
||||
|
||||
#elif defined(bpf_target_arm)
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->uregs[0])
|
||||
@@ -117,6 +167,17 @@ struct pt_regs;
|
||||
#define PT_REGS_SP(x) ((x)->uregs[13])
|
||||
#define PT_REGS_IP(x) ((x)->uregs[12])
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), uregs[0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), uregs[1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), uregs[2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), uregs[3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), uregs[4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), uregs[14])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), uregs[11])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), uregs[0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), uregs[13])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), uregs[12])
|
||||
|
||||
#elif defined(bpf_target_arm64)
|
||||
|
||||
/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */
|
||||
@@ -134,6 +195,17 @@ struct pt_regs;
|
||||
#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)
|
||||
#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[30])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[29])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), pc)
|
||||
|
||||
#elif defined(bpf_target_mips)
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->regs[4])
|
||||
@@ -147,6 +219,17 @@ struct pt_regs;
|
||||
#define PT_REGS_SP(x) ((x)->regs[29])
|
||||
#define PT_REGS_IP(x) ((x)->cp0_epc)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), regs[4])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), regs[5])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), regs[6])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), regs[7])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), regs[8])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), regs[31])
|
||||
#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), regs[30])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), regs[1])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), regs[29])
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), cp0_epc)
|
||||
|
||||
#elif defined(bpf_target_powerpc)
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->gpr[3])
|
||||
@@ -158,6 +241,15 @@ struct pt_regs;
|
||||
#define PT_REGS_SP(x) ((x)->sp)
|
||||
#define PT_REGS_IP(x) ((x)->nip)
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), gpr[3])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), gpr[4])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), gpr[5])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), gpr[6])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), gpr[7])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), gpr[3])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), nip)
|
||||
|
||||
#elif defined(bpf_target_sparc)
|
||||
|
||||
#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])
|
||||
@@ -169,11 +261,22 @@ struct pt_regs;
|
||||
#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])
|
||||
#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])
|
||||
|
||||
#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])
|
||||
#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I1])
|
||||
#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I2])
|
||||
#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I3])
|
||||
#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I4])
|
||||
#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I7])
|
||||
#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])
|
||||
#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), u_regs[UREG_FP])
|
||||
|
||||
/* Should this also be a bpf_target check for the sparc case? */
|
||||
#if defined(__arch64__)
|
||||
#define PT_REGS_IP(x) ((x)->tpc)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), tpc)
|
||||
#else
|
||||
#define PT_REGS_IP(x) ((x)->pc)
|
||||
#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -192,4 +295,122 @@ struct pt_regs;
|
||||
(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
|
||||
#endif
|
||||
|
||||
#define ___bpf_concat(a, b) a ## b
|
||||
#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
|
||||
#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
|
||||
#define ___bpf_narg(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
#define ___bpf_empty(...) \
|
||||
___bpf_nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)
|
||||
|
||||
#define ___bpf_ctx_cast0() ctx
|
||||
#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]
|
||||
#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1]
|
||||
#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2]
|
||||
#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3]
|
||||
#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4]
|
||||
#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5]
|
||||
#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6]
|
||||
#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7]
|
||||
#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8]
|
||||
#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9]
|
||||
#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10]
|
||||
#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11]
|
||||
#define ___bpf_ctx_cast(args...) \
|
||||
___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and
|
||||
* similar kinds of BPF programs, that accept input arguments as a single
|
||||
* pointer to untyped u64 array, where each u64 can actually be a typed
|
||||
* pointer or integer of different size. Instead of requring user to write
|
||||
* manual casts and work with array elements by index, BPF_PROG macro
|
||||
* allows user to declare a list of named and typed input arguments in the
|
||||
* same syntax as for normal C function. All the casting is hidden and
|
||||
* performed transparently, while user code can just assume working with
|
||||
* function arguments of specified type and name.
|
||||
*
|
||||
* Original raw context argument is preserved as well as 'ctx' argument.
|
||||
* This is useful when using BPF helpers that expect original context
|
||||
* as one of the parameters (e.g., for bpf_perf_event_output()).
|
||||
*/
|
||||
#define BPF_PROG(name, args...) \
|
||||
name(unsigned long long *ctx); \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(unsigned long long *ctx, ##args); \
|
||||
typeof(name(0)) name(unsigned long long *ctx) \
|
||||
{ \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
return ____##name(___bpf_ctx_cast(args)); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
} \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(unsigned long long *ctx, ##args)
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
#define ___bpf_kprobe_args0() ctx
|
||||
#define ___bpf_kprobe_args1(x) \
|
||||
___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)
|
||||
#define ___bpf_kprobe_args2(x, args...) \
|
||||
___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)
|
||||
#define ___bpf_kprobe_args3(x, args...) \
|
||||
___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)
|
||||
#define ___bpf_kprobe_args4(x, args...) \
|
||||
___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)
|
||||
#define ___bpf_kprobe_args5(x, args...) \
|
||||
___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)
|
||||
#define ___bpf_kprobe_args(args...) \
|
||||
___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for
|
||||
* tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific
|
||||
* low-level way of getting kprobe input arguments from struct pt_regs, and
|
||||
* provides a familiar typed and named function arguments syntax and
|
||||
* semantics of accessing kprobe input paremeters.
|
||||
*
|
||||
* Original struct pt_regs* context is preserved as 'ctx' argument. This might
|
||||
* be necessary when using BPF helpers like bpf_perf_event_output().
|
||||
*/
|
||||
#define BPF_KPROBE(name, args...) \
|
||||
name(struct pt_regs *ctx); \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args); \
|
||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
{ \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
return ____##name(___bpf_kprobe_args(args)); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
} \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#define ___bpf_kretprobe_args0() ctx
|
||||
#define ___bpf_kretprobe_args1(x) \
|
||||
___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)
|
||||
#define ___bpf_kretprobe_args(args...) \
|
||||
___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)
|
||||
|
||||
/*
|
||||
* BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional
|
||||
* return value (in addition to `struct pt_regs *ctx`), but no input
|
||||
* arguments, because they will be clobbered by the time probed function
|
||||
* returns.
|
||||
*/
|
||||
#define BPF_KRETPROBE(name, args...) \
|
||||
name(struct pt_regs *ctx); \
|
||||
static __attribute__((always_inline)) typeof(name(0)) \
|
||||
____##name(struct pt_regs *ctx, ##args); \
|
||||
typeof(name(0)) name(struct pt_regs *ctx) \
|
||||
{ \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
|
||||
return ____##name(___bpf_kretprobe_args(args)); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
} \
|
||||
static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)
|
||||
|
||||
#endif
|
||||
|
||||
20
src/btf.c
20
src/btf.c
@@ -657,22 +657,32 @@ int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
|
||||
|
||||
int btf__load(struct btf *btf)
|
||||
{
|
||||
__u32 log_buf_size = BPF_LOG_BUF_SIZE;
|
||||
__u32 log_buf_size = 0;
|
||||
char *log_buf = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (btf->fd >= 0)
|
||||
return -EEXIST;
|
||||
|
||||
log_buf = malloc(log_buf_size);
|
||||
if (!log_buf)
|
||||
return -ENOMEM;
|
||||
retry_load:
|
||||
if (log_buf_size) {
|
||||
log_buf = malloc(log_buf_size);
|
||||
if (!log_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
*log_buf = 0;
|
||||
*log_buf = 0;
|
||||
}
|
||||
|
||||
btf->fd = bpf_load_btf(btf->data, btf->data_size,
|
||||
log_buf, log_buf_size, false);
|
||||
if (btf->fd < 0) {
|
||||
if (!log_buf || errno == ENOSPC) {
|
||||
log_buf_size = max((__u32)BPF_LOG_BUF_SIZE,
|
||||
log_buf_size << 1);
|
||||
free(log_buf);
|
||||
goto retry_load;
|
||||
}
|
||||
|
||||
err = -errno;
|
||||
pr_warn("Error loading BTF: %s(%d)\n", strerror(errno), errno);
|
||||
if (*log_buf)
|
||||
|
||||
@@ -916,13 +916,13 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
||||
/* enumerators share namespace with typedef idents */
|
||||
dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
|
||||
if (dup_cnt > 1) {
|
||||
btf_dump_printf(d, "\n%s%s___%zu = %d,",
|
||||
btf_dump_printf(d, "\n%s%s___%zu = %u,",
|
||||
pfx(lvl + 1), name, dup_cnt,
|
||||
(__s32)v->val);
|
||||
(__u32)v->val);
|
||||
} else {
|
||||
btf_dump_printf(d, "\n%s%s = %d,",
|
||||
btf_dump_printf(d, "\n%s%s = %u,",
|
||||
pfx(lvl + 1), name,
|
||||
(__s32)v->val);
|
||||
(__u32)v->val);
|
||||
}
|
||||
}
|
||||
btf_dump_printf(d, "\n%s}", pfx(lvl));
|
||||
@@ -1030,7 +1030,7 @@ int btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
if (!OPTS_VALID(opts, btf_dump_emit_type_decl_opts))
|
||||
return -EINVAL;
|
||||
|
||||
fname = OPTS_GET(opts, field_name, NULL);
|
||||
fname = OPTS_GET(opts, field_name, "");
|
||||
lvl = OPTS_GET(opts, indent_level, 0);
|
||||
btf_dump_emit_type_decl(d, id, fname, lvl);
|
||||
return 0;
|
||||
|
||||
446
src/libbpf.c
446
src/libbpf.c
@@ -24,6 +24,7 @@
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -177,6 +178,8 @@ struct bpf_capabilities {
|
||||
__u32 array_mmap:1;
|
||||
/* BTF_FUNC_GLOBAL is supported */
|
||||
__u32 btf_func_global:1;
|
||||
/* kernel support for expected_attach_type in BPF_PROG_LOAD */
|
||||
__u32 exp_attach_type:1;
|
||||
};
|
||||
|
||||
enum reloc_type {
|
||||
@@ -193,6 +196,22 @@ struct reloc_desc {
|
||||
int sym_off;
|
||||
};
|
||||
|
||||
struct bpf_sec_def;
|
||||
|
||||
typedef struct bpf_link *(*attach_fn_t)(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
|
||||
struct bpf_sec_def {
|
||||
const char *sec;
|
||||
size_t len;
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
bool is_exp_attach_type_optional;
|
||||
bool is_attachable;
|
||||
bool is_attach_btf;
|
||||
attach_fn_t attach_fn;
|
||||
};
|
||||
|
||||
/*
|
||||
* bpf_prog should be a better name but it has been used in
|
||||
* linux/filter.h.
|
||||
@@ -203,6 +222,7 @@ struct bpf_program {
|
||||
char *name;
|
||||
int prog_ifindex;
|
||||
char *section_name;
|
||||
const struct bpf_sec_def *sec_def;
|
||||
/* section_name with / replaced by _; makes recursive pinning
|
||||
* in bpf_object__pin_programs easier
|
||||
*/
|
||||
@@ -1283,7 +1303,7 @@ static size_t bpf_map_mmap_sz(const struct bpf_map *map)
|
||||
static char *internal_map_name(struct bpf_object *obj,
|
||||
enum libbpf_map_type type)
|
||||
{
|
||||
char map_name[BPF_OBJ_NAME_LEN];
|
||||
char map_name[BPF_OBJ_NAME_LEN], *p;
|
||||
const char *sfx = libbpf_type_to_btf_name[type];
|
||||
int sfx_len = max((size_t)7, strlen(sfx));
|
||||
int pfx_len = min((size_t)BPF_OBJ_NAME_LEN - sfx_len - 1,
|
||||
@@ -1292,6 +1312,11 @@ static char *internal_map_name(struct bpf_object *obj,
|
||||
snprintf(map_name, sizeof(map_name), "%.*s%.*s", pfx_len, obj->name,
|
||||
sfx_len, libbpf_type_to_btf_name[type]);
|
||||
|
||||
/* sanitise map name to characters allowed by kernel */
|
||||
for (p = map_name; *p && p < map_name + sizeof(map_name); p++)
|
||||
if (!isalnum(*p) && *p != '_' && *p != '.')
|
||||
*p = '_';
|
||||
|
||||
return strdup(map_name);
|
||||
}
|
||||
|
||||
@@ -1839,7 +1864,6 @@ resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id)
|
||||
* type definition, while using only sizeof(void *) space in ELF data section.
|
||||
*/
|
||||
static bool get_map_field_int(const char *map_name, const struct btf *btf,
|
||||
const struct btf_type *def,
|
||||
const struct btf_member *m, __u32 *res)
|
||||
{
|
||||
const struct btf_type *t = skip_mods_and_typedefs(btf, m->type, NULL);
|
||||
@@ -1966,19 +1990,19 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strcmp(name, "type") == 0) {
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
if (!get_map_field_int(map_name, obj->btf, m,
|
||||
&map->def.type))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found type = %u.\n",
|
||||
map_name, map->def.type);
|
||||
} else if (strcmp(name, "max_entries") == 0) {
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
if (!get_map_field_int(map_name, obj->btf, m,
|
||||
&map->def.max_entries))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found max_entries = %u.\n",
|
||||
map_name, map->def.max_entries);
|
||||
} else if (strcmp(name, "map_flags") == 0) {
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
if (!get_map_field_int(map_name, obj->btf, m,
|
||||
&map->def.map_flags))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found map_flags = %u.\n",
|
||||
@@ -1986,8 +2010,7 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
|
||||
} else if (strcmp(name, "key_size") == 0) {
|
||||
__u32 sz;
|
||||
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
&sz))
|
||||
if (!get_map_field_int(map_name, obj->btf, m, &sz))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found key_size = %u.\n",
|
||||
map_name, sz);
|
||||
@@ -2029,8 +2052,7 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
|
||||
} else if (strcmp(name, "value_size") == 0) {
|
||||
__u32 sz;
|
||||
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
&sz))
|
||||
if (!get_map_field_int(map_name, obj->btf, m, &sz))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found value_size = %u.\n",
|
||||
map_name, sz);
|
||||
@@ -2073,8 +2095,7 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
|
||||
__u32 val;
|
||||
int err;
|
||||
|
||||
if (!get_map_field_int(map_name, obj->btf, def, m,
|
||||
&val))
|
||||
if (!get_map_field_int(map_name, obj->btf, m, &val))
|
||||
return -EINVAL;
|
||||
pr_debug("map '%s': found pinning = %u.\n",
|
||||
map_name, val);
|
||||
@@ -2278,11 +2299,16 @@ static void bpf_object__sanitize_btf_ext(struct bpf_object *obj)
|
||||
}
|
||||
}
|
||||
|
||||
static bool bpf_object__is_btf_mandatory(const struct bpf_object *obj)
|
||||
static bool libbpf_needs_btf(const struct bpf_object *obj)
|
||||
{
|
||||
return obj->efile.btf_maps_shndx >= 0 ||
|
||||
obj->efile.st_ops_shndx >= 0 ||
|
||||
obj->nr_extern > 0;
|
||||
obj->efile.st_ops_shndx >= 0 ||
|
||||
obj->nr_extern > 0;
|
||||
}
|
||||
|
||||
static bool kernel_needs_btf(const struct bpf_object *obj)
|
||||
{
|
||||
return obj->efile.st_ops_shndx >= 0;
|
||||
}
|
||||
|
||||
static int bpf_object__init_btf(struct bpf_object *obj,
|
||||
@@ -2318,7 +2344,7 @@ static int bpf_object__init_btf(struct bpf_object *obj,
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (err && bpf_object__is_btf_mandatory(obj)) {
|
||||
if (err && libbpf_needs_btf(obj)) {
|
||||
pr_warn("BTF is required, but is missing or corrupted.\n");
|
||||
return err;
|
||||
}
|
||||
@@ -2342,7 +2368,7 @@ static int bpf_object__finalize_btf(struct bpf_object *obj)
|
||||
btf_ext__free(obj->btf_ext);
|
||||
obj->btf_ext = NULL;
|
||||
|
||||
if (bpf_object__is_btf_mandatory(obj)) {
|
||||
if (libbpf_needs_btf(obj)) {
|
||||
pr_warn("BTF is required, but is missing or corrupted.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
@@ -2351,7 +2377,8 @@ static int bpf_object__finalize_btf(struct bpf_object *obj)
|
||||
|
||||
static inline bool libbpf_prog_needs_vmlinux_btf(struct bpf_program *prog)
|
||||
{
|
||||
if (prog->type == BPF_PROG_TYPE_STRUCT_OPS)
|
||||
if (prog->type == BPF_PROG_TYPE_STRUCT_OPS ||
|
||||
prog->type == BPF_PROG_TYPE_LSM)
|
||||
return true;
|
||||
|
||||
/* BPF_PROG_TYPE_TRACING programs which do not attach to other programs
|
||||
@@ -2406,7 +2433,7 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
|
||||
obj->btf_ext = NULL;
|
||||
}
|
||||
|
||||
if (bpf_object__is_btf_mandatory(obj))
|
||||
if (kernel_needs_btf(obj))
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
@@ -3307,6 +3334,37 @@ static int bpf_object__probe_array_mmap(struct bpf_object *obj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_exp_attach_type(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_load_program_attr attr;
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int fd;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
/* use any valid combination of program type and (optional)
|
||||
* non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS)
|
||||
* to see if kernel supports expected_attach_type field for
|
||||
* BPF_PROG_LOAD command
|
||||
*/
|
||||
attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
|
||||
attr.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE;
|
||||
attr.insns = insns;
|
||||
attr.insns_cnt = ARRAY_SIZE(insns);
|
||||
attr.license = "GPL";
|
||||
|
||||
fd = bpf_load_program_xattr(&attr, NULL, 0);
|
||||
if (fd >= 0) {
|
||||
obj->caps.exp_attach_type = 1;
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_caps(struct bpf_object *obj)
|
||||
{
|
||||
@@ -3317,6 +3375,7 @@ bpf_object__probe_caps(struct bpf_object *obj)
|
||||
bpf_object__probe_btf_func_global,
|
||||
bpf_object__probe_btf_datasec,
|
||||
bpf_object__probe_array_mmap,
|
||||
bpf_object__probe_exp_attach_type,
|
||||
};
|
||||
int i, ret;
|
||||
|
||||
@@ -3862,6 +3921,10 @@ static struct ids_vec *bpf_core_find_cands(const struct btf *local_btf,
|
||||
if (str_is_empty(targ_name))
|
||||
continue;
|
||||
|
||||
t = skip_mods_and_typedefs(targ_btf, i, NULL);
|
||||
if (!btf_is_composite(t) && !btf_is_array(t))
|
||||
continue;
|
||||
|
||||
targ_essent_len = bpf_core_essential_name_len(targ_name);
|
||||
if (targ_essent_len != local_essent_len)
|
||||
continue;
|
||||
@@ -4840,8 +4903,8 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||
{
|
||||
struct bpf_load_program_attr load_attr;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
int log_buf_size = BPF_LOG_BUF_SIZE;
|
||||
char *log_buf;
|
||||
size_t log_buf_size = 0;
|
||||
char *log_buf = NULL;
|
||||
int btf_fd, ret;
|
||||
|
||||
if (!insns || !insns_cnt)
|
||||
@@ -4849,13 +4912,19 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||
|
||||
memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
|
||||
load_attr.prog_type = prog->type;
|
||||
load_attr.expected_attach_type = prog->expected_attach_type;
|
||||
/* old kernels might not support specifying expected_attach_type */
|
||||
if (!prog->caps->exp_attach_type && prog->sec_def &&
|
||||
prog->sec_def->is_exp_attach_type_optional)
|
||||
load_attr.expected_attach_type = 0;
|
||||
else
|
||||
load_attr.expected_attach_type = prog->expected_attach_type;
|
||||
if (prog->caps->name)
|
||||
load_attr.name = prog->name;
|
||||
load_attr.insns = insns;
|
||||
load_attr.insns_cnt = insns_cnt;
|
||||
load_attr.license = license;
|
||||
if (prog->type == BPF_PROG_TYPE_STRUCT_OPS) {
|
||||
if (prog->type == BPF_PROG_TYPE_STRUCT_OPS ||
|
||||
prog->type == BPF_PROG_TYPE_LSM) {
|
||||
load_attr.attach_btf_id = prog->attach_btf_id;
|
||||
} else if (prog->type == BPF_PROG_TYPE_TRACING ||
|
||||
prog->type == BPF_PROG_TYPE_EXT) {
|
||||
@@ -4881,22 +4950,28 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||
load_attr.prog_flags = prog->prog_flags;
|
||||
|
||||
retry_load:
|
||||
log_buf = malloc(log_buf_size);
|
||||
if (!log_buf)
|
||||
pr_warn("Alloc log buffer for bpf loader error, continue without log\n");
|
||||
if (log_buf_size) {
|
||||
log_buf = malloc(log_buf_size);
|
||||
if (!log_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
*log_buf = 0;
|
||||
}
|
||||
|
||||
ret = bpf_load_program_xattr(&load_attr, log_buf, log_buf_size);
|
||||
|
||||
if (ret >= 0) {
|
||||
if (load_attr.log_level)
|
||||
if (log_buf && load_attr.log_level)
|
||||
pr_debug("verifier log:\n%s", log_buf);
|
||||
*pfd = ret;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (errno == ENOSPC) {
|
||||
log_buf_size <<= 1;
|
||||
if (!log_buf || errno == ENOSPC) {
|
||||
log_buf_size = max((size_t)BPF_LOG_BUF_SIZE,
|
||||
log_buf_size << 1);
|
||||
|
||||
free(log_buf);
|
||||
goto retry_load;
|
||||
}
|
||||
@@ -4939,8 +5014,9 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
|
||||
{
|
||||
int err = 0, fd, i, btf_id;
|
||||
|
||||
if (prog->type == BPF_PROG_TYPE_TRACING ||
|
||||
prog->type == BPF_PROG_TYPE_EXT) {
|
||||
if ((prog->type == BPF_PROG_TYPE_TRACING ||
|
||||
prog->type == BPF_PROG_TYPE_LSM ||
|
||||
prog->type == BPF_PROG_TYPE_EXT) && !prog->attach_btf_id) {
|
||||
btf_id = libbpf_find_attach_btf_id(prog);
|
||||
if (btf_id <= 0)
|
||||
return btf_id;
|
||||
@@ -5042,6 +5118,8 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bpf_sec_def *find_sec_def(const char *sec_name);
|
||||
|
||||
static struct bpf_object *
|
||||
__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
|
||||
const struct bpf_object_open_opts *opts)
|
||||
@@ -5097,24 +5175,17 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
|
||||
bpf_object__elf_finish(obj);
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type attach_type;
|
||||
|
||||
if (prog->type != BPF_PROG_TYPE_UNSPEC)
|
||||
continue;
|
||||
|
||||
err = libbpf_prog_type_by_name(prog->section_name, &prog_type,
|
||||
&attach_type);
|
||||
if (err == -ESRCH)
|
||||
prog->sec_def = find_sec_def(prog->section_name);
|
||||
if (!prog->sec_def)
|
||||
/* couldn't guess, but user might manually specify */
|
||||
continue;
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
bpf_program__set_type(prog, prog_type);
|
||||
bpf_program__set_expected_attach_type(prog, attach_type);
|
||||
if (prog_type == BPF_PROG_TYPE_TRACING ||
|
||||
prog_type == BPF_PROG_TYPE_EXT)
|
||||
bpf_program__set_type(prog, prog->sec_def->prog_type);
|
||||
bpf_program__set_expected_attach_type(prog,
|
||||
prog->sec_def->expected_attach_type);
|
||||
|
||||
if (prog->sec_def->prog_type == BPF_PROG_TYPE_TRACING ||
|
||||
prog->sec_def->prog_type == BPF_PROG_TYPE_EXT)
|
||||
prog->attach_prog_fd = OPTS_GET(opts, attach_prog_fd, 0);
|
||||
}
|
||||
|
||||
@@ -6179,6 +6250,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
|
||||
} \
|
||||
|
||||
BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
|
||||
BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
|
||||
BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
|
||||
BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
|
||||
BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
|
||||
@@ -6202,23 +6274,32 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
prog->expected_attach_type = type;
|
||||
}
|
||||
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, btf, atype) \
|
||||
{ string, sizeof(string) - 1, ptype, eatype, is_attachable, btf, atype }
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype_optional, \
|
||||
attachable, attach_btf) \
|
||||
{ \
|
||||
.sec = string, \
|
||||
.len = sizeof(string) - 1, \
|
||||
.prog_type = ptype, \
|
||||
.expected_attach_type = eatype, \
|
||||
.is_exp_attach_type_optional = eatype_optional, \
|
||||
.is_attachable = attachable, \
|
||||
.is_attach_btf = attach_btf, \
|
||||
}
|
||||
|
||||
/* Programs that can NOT be attached. */
|
||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0, 0)
|
||||
|
||||
/* Programs that can be attached. */
|
||||
#define BPF_APROG_SEC(string, ptype, atype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, 0, 1, 0, atype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, atype, true, 1, 0)
|
||||
|
||||
/* Programs that must specify expected attach type at load time. */
|
||||
#define BPF_EAPROG_SEC(string, ptype, eatype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, 0, eatype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, false, 1, 0)
|
||||
|
||||
/* Programs that use BTF to identify attach point */
|
||||
#define BPF_PROG_BTF(string, ptype, eatype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, 0, 1, 0)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, false, 0, 1)
|
||||
|
||||
/* Programs that can be attached but attach type can't be identified by section
|
||||
* name. Kept for backward compatibility.
|
||||
@@ -6232,11 +6313,6 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
struct bpf_sec_def;
|
||||
|
||||
typedef struct bpf_link *(*attach_fn_t)(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
|
||||
static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
|
||||
@@ -6245,17 +6321,8 @@ static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
|
||||
struct bpf_sec_def {
|
||||
const char *sec;
|
||||
size_t len;
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
bool is_attachable;
|
||||
bool is_attach_btf;
|
||||
enum bpf_attach_type attach_type;
|
||||
attach_fn_t attach_fn;
|
||||
};
|
||||
static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog);
|
||||
|
||||
static const struct bpf_sec_def section_defs[] = {
|
||||
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
||||
@@ -6284,6 +6351,10 @@ static const struct bpf_sec_def section_defs[] = {
|
||||
.expected_attach_type = BPF_TRACE_FENTRY,
|
||||
.is_attach_btf = true,
|
||||
.attach_fn = attach_trace),
|
||||
SEC_DEF("fmod_ret/", TRACING,
|
||||
.expected_attach_type = BPF_MODIFY_RETURN,
|
||||
.is_attach_btf = true,
|
||||
.attach_fn = attach_trace),
|
||||
SEC_DEF("fexit/", TRACING,
|
||||
.expected_attach_type = BPF_TRACE_FEXIT,
|
||||
.is_attach_btf = true,
|
||||
@@ -6291,6 +6362,10 @@ static const struct bpf_sec_def section_defs[] = {
|
||||
SEC_DEF("freplace/", EXT,
|
||||
.is_attach_btf = true,
|
||||
.attach_fn = attach_trace),
|
||||
SEC_DEF("lsm/", LSM,
|
||||
.is_attach_btf = true,
|
||||
.expected_attach_type = BPF_LSM_MAC,
|
||||
.attach_fn = attach_lsm),
|
||||
BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP),
|
||||
BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT),
|
||||
BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN),
|
||||
@@ -6553,6 +6628,7 @@ invalid_prog:
|
||||
}
|
||||
|
||||
#define BTF_TRACE_PREFIX "btf_trace_"
|
||||
#define BTF_LSM_PREFIX "bpf_lsm_"
|
||||
#define BTF_MAX_NAME_SIZE 128
|
||||
|
||||
static int find_btf_by_prefix_kind(const struct btf *btf, const char *prefix,
|
||||
@@ -6580,9 +6656,15 @@ static inline int __find_vmlinux_btf_id(struct btf *btf, const char *name,
|
||||
if (attach_type == BPF_TRACE_RAW_TP)
|
||||
err = find_btf_by_prefix_kind(btf, BTF_TRACE_PREFIX, name,
|
||||
BTF_KIND_TYPEDEF);
|
||||
else if (attach_type == BPF_LSM_MAC)
|
||||
err = find_btf_by_prefix_kind(btf, BTF_LSM_PREFIX, name,
|
||||
BTF_KIND_FUNC);
|
||||
else
|
||||
err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
|
||||
|
||||
if (err <= 0)
|
||||
pr_warn("%s is not found in vmlinux BTF\n", name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -6655,8 +6737,6 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog)
|
||||
err = __find_vmlinux_btf_id(prog->obj->btf_vmlinux,
|
||||
name + section_defs[i].len,
|
||||
attach_type);
|
||||
if (err <= 0)
|
||||
pr_warn("%s is not found in vmlinux BTF\n", name);
|
||||
return err;
|
||||
}
|
||||
pr_warn("failed to identify btf_id based on ELF section name '%s'\n", name);
|
||||
@@ -6677,7 +6757,7 @@ int libbpf_attach_type_by_name(const char *name,
|
||||
continue;
|
||||
if (!section_defs[i].is_attachable)
|
||||
return -EINVAL;
|
||||
*attach_type = section_defs[i].attach_type;
|
||||
*attach_type = section_defs[i].expected_attach_type;
|
||||
return 0;
|
||||
}
|
||||
pr_debug("failed to guess attach type based on ELF section name '%s'\n", name);
|
||||
@@ -6736,6 +6816,17 @@ void *bpf_map__priv(const struct bpf_map *map)
|
||||
return map ? map->priv : ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
int bpf_map__set_initial_value(struct bpf_map *map,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
if (!map->mmaped || map->libbpf_type == LIBBPF_MAP_KCONFIG ||
|
||||
size != map->def.value_size || map->fd >= 0)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(map->mmaped, data, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bpf_map__is_offload_neutral(const struct bpf_map *map)
|
||||
{
|
||||
return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
|
||||
@@ -6926,9 +7017,17 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
||||
struct bpf_link {
|
||||
int (*detach)(struct bpf_link *link);
|
||||
int (*destroy)(struct bpf_link *link);
|
||||
char *pin_path; /* NULL, if not pinned */
|
||||
int fd; /* hook FD, -1 if not applicable */
|
||||
bool disconnected;
|
||||
};
|
||||
|
||||
/* Replace link's underlying BPF program with the new one */
|
||||
int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog)
|
||||
{
|
||||
return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
|
||||
}
|
||||
|
||||
/* Release "ownership" of underlying BPF resource (typically, BPF program
|
||||
* attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected
|
||||
* link, when destructed through bpf_link__destroy() call won't attempt to
|
||||
@@ -6955,26 +7054,109 @@ int bpf_link__destroy(struct bpf_link *link)
|
||||
err = link->detach(link);
|
||||
if (link->destroy)
|
||||
link->destroy(link);
|
||||
if (link->pin_path)
|
||||
free(link->pin_path);
|
||||
free(link);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct bpf_link_fd {
|
||||
struct bpf_link link; /* has to be at the top of struct */
|
||||
int fd; /* hook FD */
|
||||
};
|
||||
int bpf_link__fd(const struct bpf_link *link)
|
||||
{
|
||||
return link->fd;
|
||||
}
|
||||
|
||||
const char *bpf_link__pin_path(const struct bpf_link *link)
|
||||
{
|
||||
return link->pin_path;
|
||||
}
|
||||
|
||||
static int bpf_link__detach_fd(struct bpf_link *link)
|
||||
{
|
||||
return close(link->fd);
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_link__open(const char *path)
|
||||
{
|
||||
struct bpf_link *link;
|
||||
int fd;
|
||||
|
||||
fd = bpf_obj_get(path);
|
||||
if (fd < 0) {
|
||||
fd = -errno;
|
||||
pr_warn("failed to open link at %s: %d\n", path, fd);
|
||||
return ERR_PTR(fd);
|
||||
}
|
||||
|
||||
link = calloc(1, sizeof(*link));
|
||||
if (!link) {
|
||||
close(fd);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
link->detach = &bpf_link__detach_fd;
|
||||
link->fd = fd;
|
||||
|
||||
link->pin_path = strdup(path);
|
||||
if (!link->pin_path) {
|
||||
bpf_link__destroy(link);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
int bpf_link__pin(struct bpf_link *link, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (link->pin_path)
|
||||
return -EBUSY;
|
||||
err = make_parent_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
link->pin_path = strdup(path);
|
||||
if (!link->pin_path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (bpf_obj_pin(link->fd, link->pin_path)) {
|
||||
err = -errno;
|
||||
zfree(&link->pin_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
pr_debug("link fd=%d: pinned at %s\n", link->fd, link->pin_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_link__unpin(struct bpf_link *link)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!link->pin_path)
|
||||
return -EINVAL;
|
||||
|
||||
err = unlink(link->pin_path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
|
||||
pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path);
|
||||
zfree(&link->pin_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_link__detach_perf_event(struct bpf_link *link)
|
||||
{
|
||||
struct bpf_link_fd *l = (void *)link;
|
||||
int err;
|
||||
|
||||
err = ioctl(l->fd, PERF_EVENT_IOC_DISABLE, 0);
|
||||
err = ioctl(link->fd, PERF_EVENT_IOC_DISABLE, 0);
|
||||
if (err)
|
||||
err = -errno;
|
||||
|
||||
close(l->fd);
|
||||
close(link->fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -6982,7 +7164,7 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog,
|
||||
int pfd)
|
||||
{
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_link_fd *link;
|
||||
struct bpf_link *link;
|
||||
int prog_fd, err;
|
||||
|
||||
if (pfd < 0) {
|
||||
@@ -7000,7 +7182,7 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog,
|
||||
link = calloc(1, sizeof(*link));
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
link->link.detach = &bpf_link__detach_perf_event;
|
||||
link->detach = &bpf_link__detach_perf_event;
|
||||
link->fd = pfd;
|
||||
|
||||
if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) {
|
||||
@@ -7019,7 +7201,7 @@ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog,
|
||||
libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return (struct bpf_link *)link;
|
||||
return link;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7307,18 +7489,11 @@ out:
|
||||
return link;
|
||||
}
|
||||
|
||||
static int bpf_link__detach_fd(struct bpf_link *link)
|
||||
{
|
||||
struct bpf_link_fd *l = (void *)link;
|
||||
|
||||
return close(l->fd);
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||
const char *tp_name)
|
||||
{
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_link_fd *link;
|
||||
struct bpf_link *link;
|
||||
int prog_fd, pfd;
|
||||
|
||||
prog_fd = bpf_program__fd(prog);
|
||||
@@ -7331,7 +7506,7 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||
link = calloc(1, sizeof(*link));
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
link->link.detach = &bpf_link__detach_fd;
|
||||
link->detach = &bpf_link__detach_fd;
|
||||
|
||||
pfd = bpf_raw_tracepoint_open(tp_name, prog_fd);
|
||||
if (pfd < 0) {
|
||||
@@ -7343,7 +7518,7 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||
return ERR_PTR(pfd);
|
||||
}
|
||||
link->fd = pfd;
|
||||
return (struct bpf_link *)link;
|
||||
return link;
|
||||
}
|
||||
|
||||
static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
|
||||
@@ -7354,10 +7529,11 @@ static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
|
||||
return bpf_program__attach_raw_tracepoint(prog, tp_name);
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
|
||||
/* Common logic for all BPF program types that attach to a btf_id */
|
||||
static struct bpf_link *bpf_program__attach_btf_id(struct bpf_program *prog)
|
||||
{
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_link_fd *link;
|
||||
struct bpf_link *link;
|
||||
int prog_fd, pfd;
|
||||
|
||||
prog_fd = bpf_program__fd(prog);
|
||||
@@ -7370,13 +7546,13 @@ struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
|
||||
link = calloc(1, sizeof(*link));
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
link->link.detach = &bpf_link__detach_fd;
|
||||
link->detach = &bpf_link__detach_fd;
|
||||
|
||||
pfd = bpf_raw_tracepoint_open(NULL, prog_fd);
|
||||
if (pfd < 0) {
|
||||
pfd = -errno;
|
||||
free(link);
|
||||
pr_warn("program '%s': failed to attach to trace: %s\n",
|
||||
pr_warn("program '%s': failed to attach: %s\n",
|
||||
bpf_program__title(prog, false),
|
||||
libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
|
||||
return ERR_PTR(pfd);
|
||||
@@ -7385,12 +7561,62 @@ struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
|
||||
return (struct bpf_link *)link;
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
|
||||
{
|
||||
return bpf_program__attach_btf_id(prog);
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog)
|
||||
{
|
||||
return bpf_program__attach_btf_id(prog);
|
||||
}
|
||||
|
||||
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog)
|
||||
{
|
||||
return bpf_program__attach_trace(prog);
|
||||
}
|
||||
|
||||
static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec,
|
||||
struct bpf_program *prog)
|
||||
{
|
||||
return bpf_program__attach_lsm(prog);
|
||||
}
|
||||
|
||||
struct bpf_link *
|
||||
bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
char errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_link *link;
|
||||
int prog_fd, link_fd;
|
||||
|
||||
prog_fd = bpf_program__fd(prog);
|
||||
if (prog_fd < 0) {
|
||||
pr_warn("program '%s': can't attach before loaded\n",
|
||||
bpf_program__title(prog, false));
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
link = calloc(1, sizeof(*link));
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
link->detach = &bpf_link__detach_fd;
|
||||
|
||||
attach_type = bpf_program__get_expected_attach_type(prog);
|
||||
link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, NULL);
|
||||
if (link_fd < 0) {
|
||||
link_fd = -errno;
|
||||
free(link);
|
||||
pr_warn("program '%s': failed to attach to cgroup: %s\n",
|
||||
bpf_program__title(prog, false),
|
||||
libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
|
||||
return ERR_PTR(link_fd);
|
||||
}
|
||||
link->fd = link_fd;
|
||||
return link;
|
||||
}
|
||||
|
||||
struct bpf_link *bpf_program__attach(struct bpf_program *prog)
|
||||
{
|
||||
const struct bpf_sec_def *sec_def;
|
||||
@@ -7404,10 +7630,9 @@ struct bpf_link *bpf_program__attach(struct bpf_program *prog)
|
||||
|
||||
static int bpf_link__detach_struct_ops(struct bpf_link *link)
|
||||
{
|
||||
struct bpf_link_fd *l = (void *)link;
|
||||
__u32 zero = 0;
|
||||
|
||||
if (bpf_map_delete_elem(l->fd, &zero))
|
||||
if (bpf_map_delete_elem(link->fd, &zero))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
@@ -7416,7 +7641,7 @@ static int bpf_link__detach_struct_ops(struct bpf_link *link)
|
||||
struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map)
|
||||
{
|
||||
struct bpf_struct_ops *st_ops;
|
||||
struct bpf_link_fd *link;
|
||||
struct bpf_link *link;
|
||||
__u32 i, zero = 0;
|
||||
int err;
|
||||
|
||||
@@ -7448,10 +7673,10 @@ struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
link->link.detach = bpf_link__detach_struct_ops;
|
||||
link->detach = bpf_link__detach_struct_ops;
|
||||
link->fd = map->fd;
|
||||
|
||||
return (struct bpf_link *)link;
|
||||
return link;
|
||||
}
|
||||
|
||||
enum bpf_perf_event_ret
|
||||
@@ -8132,6 +8357,31 @@ void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
|
||||
}
|
||||
}
|
||||
|
||||
int bpf_program__set_attach_target(struct bpf_program *prog,
|
||||
int attach_prog_fd,
|
||||
const char *attach_func_name)
|
||||
{
|
||||
int btf_id;
|
||||
|
||||
if (!prog || attach_prog_fd < 0 || !attach_func_name)
|
||||
return -EINVAL;
|
||||
|
||||
if (attach_prog_fd)
|
||||
btf_id = libbpf_find_prog_btf_id(attach_func_name,
|
||||
attach_prog_fd);
|
||||
else
|
||||
btf_id = __find_vmlinux_btf_id(prog->obj->btf_vmlinux,
|
||||
attach_func_name,
|
||||
prog->expected_attach_type);
|
||||
|
||||
if (btf_id < 0)
|
||||
return btf_id;
|
||||
|
||||
prog->attach_btf_id = btf_id;
|
||||
prog->attach_prog_fd = attach_prog_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz)
|
||||
{
|
||||
int err = 0, n, len, start, end = -1;
|
||||
|
||||
31
src/libbpf.h
31
src/libbpf.h
@@ -219,6 +219,13 @@ LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
||||
|
||||
struct bpf_link;
|
||||
|
||||
LIBBPF_API struct bpf_link *bpf_link__open(const char *path);
|
||||
LIBBPF_API int bpf_link__fd(const struct bpf_link *link);
|
||||
LIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link);
|
||||
LIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path);
|
||||
LIBBPF_API int bpf_link__unpin(struct bpf_link *link);
|
||||
LIBBPF_API int bpf_link__update_program(struct bpf_link *link,
|
||||
struct bpf_program *prog);
|
||||
LIBBPF_API void bpf_link__disconnect(struct bpf_link *link);
|
||||
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
|
||||
|
||||
@@ -240,11 +247,17 @@ bpf_program__attach_tracepoint(struct bpf_program *prog,
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
|
||||
const char *tp_name);
|
||||
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_trace(struct bpf_program *prog);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_lsm(struct bpf_program *prog);
|
||||
LIBBPF_API struct bpf_link *
|
||||
bpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);
|
||||
|
||||
struct bpf_map;
|
||||
|
||||
LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);
|
||||
|
||||
struct bpf_insn;
|
||||
|
||||
/*
|
||||
@@ -316,6 +329,7 @@ LIBBPF_API int bpf_program__set_socket_filter(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_tracepoint(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_raw_tracepoint(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_kprobe(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_lsm(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);
|
||||
@@ -334,10 +348,15 @@ LIBBPF_API void
|
||||
bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
enum bpf_attach_type type);
|
||||
|
||||
LIBBPF_API int
|
||||
bpf_program__set_attach_target(struct bpf_program *prog, int attach_prog_fd,
|
||||
const char *attach_func_name);
|
||||
|
||||
LIBBPF_API bool bpf_program__is_socket_filter(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_tracepoint(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_raw_tracepoint(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_kprobe(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_lsm(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_sched_cls(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
|
||||
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
|
||||
@@ -398,6 +417,8 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
|
||||
LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
||||
bpf_map_clear_priv_t clear_priv);
|
||||
LIBBPF_API void *bpf_map__priv(const struct bpf_map *map);
|
||||
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
|
||||
const void *data, size_t size);
|
||||
LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
|
||||
LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
|
||||
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
|
||||
@@ -435,7 +456,15 @@ struct xdp_link_info {
|
||||
__u8 attach_mode;
|
||||
};
|
||||
|
||||
struct bpf_xdp_set_link_opts {
|
||||
size_t sz;
|
||||
int old_fd;
|
||||
};
|
||||
#define bpf_xdp_set_link_opts__last_field old_fd
|
||||
|
||||
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
|
||||
LIBBPF_API int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
|
||||
const struct bpf_xdp_set_link_opts *opts);
|
||||
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
|
||||
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||
size_t info_size, __u32 flags);
|
||||
|
||||
@@ -235,3 +235,22 @@ LIBBPF_0.0.7 {
|
||||
btf__align_of;
|
||||
libbpf_find_kernel_btf;
|
||||
} LIBBPF_0.0.6;
|
||||
|
||||
LIBBPF_0.0.8 {
|
||||
global:
|
||||
bpf_link__fd;
|
||||
bpf_link__open;
|
||||
bpf_link__pin;
|
||||
bpf_link__pin_path;
|
||||
bpf_link__unpin;
|
||||
bpf_link__update_program;
|
||||
bpf_link_create;
|
||||
bpf_link_update;
|
||||
bpf_map__set_initial_value;
|
||||
bpf_program__attach_cgroup;
|
||||
bpf_program__attach_lsm;
|
||||
bpf_program__is_lsm;
|
||||
bpf_program__set_attach_target;
|
||||
bpf_program__set_lsm;
|
||||
bpf_set_link_xdp_fd_opts;
|
||||
} LIBBPF_0.0.7;
|
||||
|
||||
@@ -108,6 +108,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
|
||||
case BPF_PROG_TYPE_TRACING:
|
||||
case BPF_PROG_TYPE_STRUCT_OPS:
|
||||
case BPF_PROG_TYPE_EXT:
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,8 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||
static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
|
||||
__u32 flags)
|
||||
{
|
||||
int sock, seq = 0, ret;
|
||||
struct nlattr *nla, *nla_xdp;
|
||||
@@ -141,7 +142,7 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||
struct ifinfomsg ifinfo;
|
||||
char attrbuf[64];
|
||||
} req;
|
||||
__u32 nl_pid;
|
||||
__u32 nl_pid = 0;
|
||||
|
||||
sock = libbpf_netlink_open(&nl_pid);
|
||||
if (sock < 0)
|
||||
@@ -178,6 +179,14 @@ int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||
nla->nla_len += nla_xdp->nla_len;
|
||||
}
|
||||
|
||||
if (flags & XDP_FLAGS_REPLACE) {
|
||||
nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
|
||||
nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD;
|
||||
nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd);
|
||||
memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd));
|
||||
nla->nla_len += nla_xdp->nla_len;
|
||||
}
|
||||
|
||||
req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
|
||||
|
||||
if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
|
||||
@@ -191,6 +200,29 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
|
||||
const struct bpf_xdp_set_link_opts *opts)
|
||||
{
|
||||
int old_fd = -1;
|
||||
|
||||
if (!OPTS_VALID(opts, bpf_xdp_set_link_opts))
|
||||
return -EINVAL;
|
||||
|
||||
if (OPTS_HAS(opts, old_fd)) {
|
||||
old_fd = OPTS_GET(opts, old_fd, -1);
|
||||
flags |= XDP_FLAGS_REPLACE;
|
||||
}
|
||||
|
||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd,
|
||||
old_fd,
|
||||
flags);
|
||||
}
|
||||
|
||||
int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
|
||||
{
|
||||
return __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
|
||||
}
|
||||
|
||||
static int __dump_link_nlmsg(struct nlmsghdr *nlh,
|
||||
libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
|
||||
{
|
||||
@@ -256,7 +288,7 @@ int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||
{
|
||||
struct xdp_id_md xdp_id = {};
|
||||
int sock, ret;
|
||||
__u32 nl_pid;
|
||||
__u32 nl_pid = 0;
|
||||
__u32 mask;
|
||||
|
||||
if (flags & ~XDP_FLAGS_MASK || !info_size)
|
||||
@@ -289,7 +321,7 @@ int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
|
||||
|
||||
static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
|
||||
{
|
||||
if (info->attach_mode != XDP_ATTACHED_MULTI)
|
||||
if (info->attach_mode != XDP_ATTACHED_MULTI && !flags)
|
||||
return info->prog_id;
|
||||
if (flags & XDP_FLAGS_DRV_MODE)
|
||||
return info->drv_prog_id;
|
||||
|
||||
16
src/xsk.c
16
src/xsk.c
@@ -280,7 +280,11 @@ int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
fill->consumer = map + off.fr.consumer;
|
||||
fill->flags = map + off.fr.flags;
|
||||
fill->ring = map + off.fr.desc;
|
||||
fill->cached_cons = umem->config.fill_size;
|
||||
fill->cached_prod = *fill->producer;
|
||||
/* cached_cons is "size" bigger than the real consumer pointer
|
||||
* See xsk_prod_nb_free
|
||||
*/
|
||||
fill->cached_cons = *fill->consumer + umem->config.fill_size;
|
||||
|
||||
map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||
@@ -297,6 +301,8 @@ int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
comp->consumer = map + off.cr.consumer;
|
||||
comp->flags = map + off.cr.flags;
|
||||
comp->ring = map + off.cr.desc;
|
||||
comp->cached_prod = *comp->producer;
|
||||
comp->cached_cons = *comp->consumer;
|
||||
|
||||
*umem_ptr = umem;
|
||||
return 0;
|
||||
@@ -672,6 +678,8 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
rx->consumer = rx_map + off.rx.consumer;
|
||||
rx->flags = rx_map + off.rx.flags;
|
||||
rx->ring = rx_map + off.rx.desc;
|
||||
rx->cached_prod = *rx->producer;
|
||||
rx->cached_cons = *rx->consumer;
|
||||
}
|
||||
xsk->rx = rx;
|
||||
|
||||
@@ -691,7 +699,11 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
tx->consumer = tx_map + off.tx.consumer;
|
||||
tx->flags = tx_map + off.tx.flags;
|
||||
tx->ring = tx_map + off.tx.desc;
|
||||
tx->cached_cons = xsk->config.tx_size;
|
||||
tx->cached_prod = *tx->producer;
|
||||
/* cached_cons is r->size bigger than the real consumer pointer
|
||||
* See xsk_prod_nb_free
|
||||
*/
|
||||
tx->cached_cons = *tx->consumer + xsk->config.tx_size;
|
||||
}
|
||||
xsk->tx = tx;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
|
||||
DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
|
||||
CONT_NAME="${CONT_NAME:-debian-$DEBIAN_RELEASE-$RANDOM}"
|
||||
CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
|
||||
ENV_VARS="${ENV_VARS:-}"
|
||||
DOCKER_RUN="${DOCKER_RUN:-docker run}"
|
||||
REPO_ROOT="${REPO_ROOT:-$PWD}"
|
||||
@@ -30,6 +30,10 @@ for phase in "${PHASES[@]}"; do
|
||||
SETUP)
|
||||
info "Setup phase"
|
||||
info "Using Debian $DEBIAN_RELEASE"
|
||||
|
||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
docker --version
|
||||
|
||||
docker pull debian:$DEBIAN_RELEASE
|
||||
info "Starting container $CONT_NAME"
|
||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||
@@ -57,7 +61,7 @@ for phase in "${PHASES[@]}"; do
|
||||
docker_exec mkdir build install
|
||||
docker_exec ${CC:-cc} --version
|
||||
info "build"
|
||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
docker_exec make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
info "ldd build/libbpf.so:"
|
||||
docker_exec ldd build/libbpf.so
|
||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||
@@ -65,7 +69,7 @@ for phase in "${PHASES[@]}"; do
|
||||
exit 1
|
||||
fi
|
||||
info "install"
|
||||
docker_exec make -C src OBJDIR=../build DESTDIR=../install install
|
||||
docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||
docker_exec rm -rf build install
|
||||
;;
|
||||
CLEANUP)
|
||||
|
||||
@@ -17,11 +17,11 @@ cd $REPO_ROOT
|
||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
||||
mkdir build install
|
||||
cc --version
|
||||
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
ldd build/libbpf.so
|
||||
if ! ldd build/libbpf.so | grep -q libelf; then
|
||||
echo "FAIL: No reference to libelf.so in libbpf.so!"
|
||||
exit 1
|
||||
fi
|
||||
make -C src OBJDIR=../build DESTDIR=../install install
|
||||
make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
|
||||
rm -rf build install
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
GIT_FETCH_DEPTH="${GIT_FETCH_DEPTH}" ${VMTEST_ROOT}/checkout_latest_kernel.sh $1
|
||||
cd $1
|
||||
cp ${VMTEST_ROOT}/configs/latest.config .config
|
||||
make -j $((4*$(nproc))) olddefconfig all
|
||||
25
travis-ci/vmtest/build_pahole.sh
Executable file
25
travis-ci/vmtest/build_pahole.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
CWD=$(pwd)
|
||||
REPO_PATH=$1
|
||||
PAHOLE_ORIGIN=https://git.kernel.org/pub/scm/devel/pahole/pahole.git
|
||||
|
||||
mkdir -p ${REPO_PATH}
|
||||
cd ${REPO_PATH}
|
||||
git init
|
||||
git remote add origin ${PAHOLE_ORIGIN}
|
||||
git fetch origin
|
||||
git checkout master
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -D__LIB=lib ..
|
||||
make -j$((4*$(nproc))) all
|
||||
sudo make install
|
||||
|
||||
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/usr/local/lib
|
||||
ldd $(which pahole)
|
||||
pahole --version
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
LLVM_VER=11
|
||||
LIBBPF_PATH="${REPO_ROOT}"
|
||||
REPO_PATH="travis-ci/vmtest/bpf-next"
|
||||
|
||||
# temporary work-around for failing tests
|
||||
rm "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c"
|
||||
|
||||
make \
|
||||
CLANG=clang-10 \
|
||||
LLC=llc-10 \
|
||||
LLVM_STRIP=llvm-strip-10 \
|
||||
CLANG=clang-${LLVM_VER} \
|
||||
LLC=llc-${LLVM_VER} \
|
||||
LLVM_STRIP=llvm-strip-${LLVM_VER} \
|
||||
VMLINUX_BTF="${VMLINUX_BTF}" \
|
||||
-C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
|
||||
-j $((4*$(nproc)))
|
||||
|
||||
@@ -17,8 +17,8 @@ if [ ! -d "${REPO_PATH}" ]; then
|
||||
cd ${REPO_PATH}
|
||||
git init
|
||||
git remote add bpf-next ${BPF_NEXT_ORIGIN}
|
||||
git fetch --depth ${GIT_FETCH_DEPTH} bpf-next
|
||||
git reset --hard ${LINUX_SHA}
|
||||
else
|
||||
cd ${REPO_PATH}
|
||||
for depth in 32 64 128; do
|
||||
git fetch --depth ${depth} bpf-next
|
||||
git reset --hard ${LINUX_SHA} && break
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
INDEX https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/INDEX
|
||||
libbpf-vmtest-rootfs-2020.01.10.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.01.10.tar.zst
|
||||
libbpf-vmtest-rootfs-2020.03.11.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.03.11.tar.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
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
mmap
|
||||
dctcp
|
||||
cubic
|
||||
bpf_tcp_ca
|
||||
bpf_verif_scale
|
||||
cgroup_attach
|
||||
pinning
|
||||
send_signal_tracepoint_thread
|
||||
test_syncookie
|
||||
select_reuseport
|
||||
send_signal
|
||||
sockopt_inherit
|
||||
strobemeta_nounroll2
|
||||
stacktrace_build_id
|
||||
tp_attach_query
|
||||
tcp_rtt
|
||||
task_fd_query_tp
|
||||
stacktrace_map
|
||||
test_global_funcs
|
||||
skb_ctx
|
||||
fexit_bpf2bpf
|
||||
# PERMANENTLY DISABLED
|
||||
bpf_tcp_ca # STRUCT_OPS is missing
|
||||
cgroup_attach_multi # BPF_F_REPLACE_PROG missing
|
||||
cgroup_link # LINK_CREATE is missing
|
||||
fentry_fexit # bpf_prog_test_tracing missing
|
||||
fentry_test # bpf_prog_test_tracing missing
|
||||
fexit_bpf2bpf # freplace is missing
|
||||
fexit_test # bpf_prog_test_tracing missing
|
||||
get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
|
||||
link_pinning # bpf_link is missing
|
||||
mmap # 5.5 kernel is too permissive with re-mmaping
|
||||
modify_return # fmod_ret is missing
|
||||
ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
|
||||
perf_branches # bpf_read_branch_records() helper is missing
|
||||
select_reuseport # UDP support is missing
|
||||
sk_assign # bpf_sk_assign helper missing
|
||||
sockmap_listen # no listen socket supportin SOCKMAP
|
||||
skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
|
||||
test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
|
||||
test_lsm # no BPF_LSM support
|
||||
vmlinux # hrtimer_nanosleep() signature changed incompatibly
|
||||
xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
|
||||
xdp_bpf2bpf # freplace is missing
|
||||
|
||||
|
||||
# TEMPORARILY DISABLED
|
||||
send_signal # flaky
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
mmap
|
||||
dctcp
|
||||
cubic
|
||||
bpf_tcp_ca
|
||||
bpf_verif_scale
|
||||
cgroup_attach
|
||||
pinning
|
||||
send_signal_tracepoint_thread
|
||||
test_syncookie
|
||||
select_reuseport
|
||||
send_signal
|
||||
sockopt_inherit
|
||||
strobemeta_nounroll2
|
||||
stacktrace_build_id
|
||||
tp_attach_query
|
||||
tcp_rtt
|
||||
task_fd_query_tp
|
||||
stacktrace_map
|
||||
@@ -1,23 +1,4 @@
|
||||
mmap
|
||||
dctcp
|
||||
cubic
|
||||
bpf_tcp_ca
|
||||
bpf_verif_scale
|
||||
cgroup_attach
|
||||
pinning
|
||||
send_signal_tracepoint_thread
|
||||
test_syncookie
|
||||
select_reuseport
|
||||
send_signal
|
||||
sockopt_inherit
|
||||
strobemeta_nounroll2
|
||||
stacktrace_build_id
|
||||
tp_attach_query
|
||||
tcp_rtt
|
||||
task_fd_query_tp
|
||||
stacktrace_map
|
||||
fentry
|
||||
test_overhead
|
||||
kfree_skb
|
||||
fexit_stress
|
||||
fexit_test
|
||||
# TEMPORARILY DISABLED
|
||||
send_signal # flaky
|
||||
test_lsm # semi-working
|
||||
sk_assign # needs better setup in Travis CI
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
148
travis-ci/vmtest/mkrootfs.sh
Executable file
148
travis-ci/vmtest/mkrootfs.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is based on drgn script for generating Arch Linux bootstrap
|
||||
# images.
|
||||
# https://github.com/osandov/drgn/blob/master/scripts/vmtest/mkrootfs.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage () {
|
||||
USAGE_STRING="usage: $0 [NAME]
|
||||
$0 -h
|
||||
|
||||
Build an Arch Linux root filesystem image for testing libbpf in a virtual
|
||||
machine.
|
||||
|
||||
The image is generated as a zstd-compressed tarball.
|
||||
|
||||
This must be run as root, as most of the installation is done in a chroot.
|
||||
|
||||
Arguments:
|
||||
NAME name of generated image file (default:
|
||||
libbpf-vmtest-rootfs-\$DATE.tar.zst)
|
||||
|
||||
Options:
|
||||
-h display this help message and exit"
|
||||
|
||||
case "$1" in
|
||||
out)
|
||||
echo "$USAGE_STRING"
|
||||
exit 0
|
||||
;;
|
||||
err)
|
||||
echo "$USAGE_STRING" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
while getopts "h" OPT; do
|
||||
case "$OPT" in
|
||||
h)
|
||||
usage out
|
||||
;;
|
||||
*)
|
||||
usage err
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ $OPTIND -eq $# ]]; then
|
||||
NAME="${!OPTIND}"
|
||||
elif [[ $OPTIND -gt $# ]]; then
|
||||
NAME="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
|
||||
else
|
||||
usage err
|
||||
fi
|
||||
|
||||
pacman_conf=
|
||||
root=
|
||||
trap 'rm -rf "$pacman_conf" "$root"' EXIT
|
||||
pacman_conf="$(mktemp -p "$PWD")"
|
||||
cat > "$pacman_conf" << "EOF"
|
||||
[options]
|
||||
Architecture = x86_64
|
||||
CheckSpace
|
||||
SigLevel = Required DatabaseOptional
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
[community]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
EOF
|
||||
root="$(mktemp -d -p "$PWD")"
|
||||
|
||||
packages=(
|
||||
busybox
|
||||
# libbpf dependencies.
|
||||
libelf
|
||||
zlib
|
||||
# selftests test_progs dependencies.
|
||||
binutils
|
||||
elfutils
|
||||
glibc
|
||||
# selftests test_verifier dependencies.
|
||||
libcap
|
||||
)
|
||||
|
||||
pacstrap -C "$pacman_conf" -cGM "$root" "${packages[@]}"
|
||||
|
||||
# Remove unnecessary files from the chroot.
|
||||
|
||||
# We don't need the pacman databases anymore.
|
||||
rm -rf "$root/var/lib/pacman/sync/"
|
||||
# We don't need D, Fortran, or Go.
|
||||
rm -f "$root/usr/lib/libgdruntime."* \
|
||||
"$root/usr/lib/libgphobos."* \
|
||||
"$root/usr/lib/libgfortran."* \
|
||||
"$root/usr/lib/libgo."*
|
||||
# We don't need any documentation.
|
||||
rm -rf "$root/usr/share/{doc,help,man,texinfo}"
|
||||
|
||||
chroot "${root}" /bin/busybox --install
|
||||
|
||||
cat > "$root/etc/fstab" << "EOF"
|
||||
dev /dev devtmpfs rw,nosuid 0 0
|
||||
proc /proc proc rw,nosuid,nodev,noexec 0 0
|
||||
sys /sys sysfs rw,nosuid,nodev,noexec 0 0
|
||||
debugfs /sys/kernel/debug debugfs mode=755,realtime 0 0
|
||||
bpffs /sys/fs/bpf bpf realtime 0 0
|
||||
EOF
|
||||
chmod 644 "$root/etc/fstab"
|
||||
|
||||
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
|
||||
|
||||
/bin/mount -a
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S10-mount"
|
||||
|
||||
cat > "$root/etc/rcS.d/S40-network" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
ip link set lo up
|
||||
EOF
|
||||
chmod 755 "$root/etc/rcS.d/S40-network"
|
||||
|
||||
cat > "$root/etc/init.d/rcS" << "EOF"
|
||||
#!/bin/sh
|
||||
|
||||
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"
|
||||
@@ -1,11 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
GIT_FETCH_DEPTH="${GIT_FETCH_DEPTH}" ${VMTEST_ROOT}/checkout_latest_kernel.sh $1
|
||||
|
||||
# Fix runqslower build
|
||||
# TODO(hex@): remove after the patch is merged from bpf to bpf-next tree
|
||||
cd $1
|
||||
wget https://lore.kernel.org/bpf/908498f794661c44dca54da9e09dc0c382df6fcb.1580425879.git.hex@fb.com/t.mbox.gz
|
||||
gunzip t.mbox.gz
|
||||
git apply t.mbox
|
||||
REPO_PATH=$1
|
||||
|
||||
${VMTEST_ROOT}/checkout_latest_kernel.sh ${REPO_PATH}
|
||||
cd ${REPO_PATH}
|
||||
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
cp ${VMTEST_ROOT}/configs/latest.config .config
|
||||
make -j $((4*$(nproc))) olddefconfig all
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
set -euxo pipefail
|
||||
|
||||
test_progs() {
|
||||
echo TEST_PROGS
|
||||
./test_progs ${BLACKLIST:+-b$BLACKLIST} ${WHITELIST:+-t$WHITELIST}
|
||||
}
|
||||
|
||||
test_maps() {
|
||||
echo TEST_MAPS
|
||||
# Allow failing on older kernels.
|
||||
./test_maps
|
||||
}
|
||||
|
||||
test_verifier() {
|
||||
echo TEST_VERIFIER
|
||||
./test_verifier
|
||||
}
|
||||
|
||||
configs_path='libbpf/travis-ci/vmtest/configs'
|
||||
blacklist_path="$configs_path/blacklist/BLACKLIST-${KERNEL}"
|
||||
if [[ -s "${blacklist_path}" ]]; then
|
||||
BLACKLIST=$(cat "${blacklist_path}" | tr '\n' ',')
|
||||
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}" | tr '\n' ',')
|
||||
WHITELIST=$(cat "${whitelist_path}" | cut -d'#' -f1 | tr -s '[:space:]' ',')
|
||||
fi
|
||||
|
||||
cd libbpf/selftests/bpf
|
||||
|
||||
echo TEST_PROGS
|
||||
./test_progs ${BLACKLIST:+-b$BLACKLIST} ${WHITELIST:+-t$WHITELIST}
|
||||
test_progs
|
||||
|
||||
if [[ "${KERNEL}" == 'latest' ]]; then
|
||||
test_maps
|
||||
test_verifier
|
||||
fi
|
||||
|
||||
30
travis-ci/vmtest/run_vmtest.sh
Executable file
30
travis-ci/vmtest/run_vmtest.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
VMTEST_SETUPCMD="PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
|
||||
|
||||
echo "KERNEL: $KERNEL"
|
||||
|
||||
# Build latest pahole
|
||||
${VMTEST_ROOT}/build_pahole.sh travis-ci/vmtest/pahole
|
||||
|
||||
# Install required packages
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main" | sudo tee -a /etc/apt/sources.list
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qq -y install clang lld llvm
|
||||
|
||||
# Build selftests (and latest kernel, if necessary)
|
||||
KERNEL="${KERNEL}" ${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
|
||||
|
||||
# Escape whitespace characters.
|
||||
setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
|
||||
|
||||
sudo adduser "${USER}" kvm
|
||||
|
||||
if [[ "${KERNEL}" = 'LATEST' ]]; then
|
||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||
else
|
||||
sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img;
|
||||
fi
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# An example of a script run on VM boot.
|
||||
# To execute it in TravisCI set VMTEST_SETUPCMD env var of .travis.yml in
|
||||
# libbpf root folder, e.g.
|
||||
# VMTEST_SETUPCMD="./${PROJECT_NAME}/travis-ci/vmtest/setup_example.sh"
|
||||
|
||||
if [ ! -z "${PROJECT_NAME}" ]; then
|
||||
echo "Running ${PROJECT_NAME} setup scripts..."
|
||||
fi
|
||||
echo "Hello, ${USER}!"
|
||||
Reference in New Issue
Block a user