mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-17 14:59:07 +08:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a26b51b1c | ||
|
|
2cc0829775 | ||
|
|
92cb475558 | ||
|
|
8b2782a1f2 | ||
|
|
886e8149a0 | ||
|
|
d275397111 | ||
|
|
ede18f80d8 | ||
|
|
07cd489681 | ||
|
|
d2f307c7f6 | ||
|
|
990cef2a0c | ||
|
|
4c2c521513 | ||
|
|
b1e911e9ba | ||
|
|
ae673dc91f | ||
|
|
5a256d12bf | ||
|
|
ae8edc7624 | ||
|
|
8f8b4a14fa | ||
|
|
476e158b07 | ||
|
|
13e1ee420e | ||
|
|
3e2bab6d2c | ||
|
|
9084f4cd4d | ||
|
|
66d20edaf0 | ||
|
|
d8d6772ab8 | ||
|
|
4397d09cd8 | ||
|
|
5771dacd3d | ||
|
|
d34efeeef1 | ||
|
|
db63a5aa5d | ||
|
|
d60f568961 | ||
|
|
e78a36f4b0 | ||
|
|
c8a7eb06bd | ||
|
|
b48c14807b | ||
|
|
a3b4055ec7 | ||
|
|
30603852f4 | ||
|
|
1a28fa5dac | ||
|
|
def5576b37 | ||
|
|
3e45a16621 | ||
|
|
2c0e53cb08 | ||
|
|
6227c6f8dd | ||
|
|
00ad180d07 | ||
|
|
715a58d593 | ||
|
|
11052fc1be | ||
|
|
97ecda3b25 | ||
|
|
342bcfa319 | ||
|
|
c020432531 | ||
|
|
99ce275b52 | ||
|
|
c0a5f7ee11 | ||
|
|
0da9ba439f | ||
|
|
c4735d9e05 | ||
|
|
563f1d3fff | ||
|
|
c5d4295fc5 | ||
|
|
b606dc725e | ||
|
|
f615047aa0 | ||
|
|
84a508a51f | ||
|
|
c59016e100 | ||
|
|
509ef92905 | ||
|
|
2c9394f2a3 | ||
|
|
0f4d83f3ab | ||
|
|
6a7b28b6a1 | ||
|
|
d76d264ac0 | ||
|
|
63a3bdf23a | ||
|
|
12fa15e89a | ||
|
|
b987dcfecb | ||
|
|
9c1ab4d070 |
1
BPF-CHECKPOINT-COMMIT
Normal file
1
BPF-CHECKPOINT-COMMIT
Normal file
@@ -0,0 +1 @@
|
||||
1bd63524593b964934a33afd442df16b8f90e2b5
|
||||
@@ -1 +1 @@
|
||||
66b5f1c439843bcbab01cc7f3854ae2742f3d1e3
|
||||
02dc96ef6c25f990452c114c59d75c368a1f4c8f
|
||||
|
||||
21
README.md
21
README.md
@@ -47,24 +47,3 @@ headers in a build directory /build/root/:
|
||||
$ cd src
|
||||
$ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
|
||||
```
|
||||
|
||||
To integrate libbpf into a project which uses Meson building system define
|
||||
`[wrap-git]` file in `subprojects` folder.
|
||||
To add libbpf dependency to the parent parent project, e.g. for
|
||||
libbpf_static_dep:
|
||||
```
|
||||
libbpf_obj = subproject('libbpf', required : true)
|
||||
libbpf_static_dep = libbpf_proj.get_variable('libbpf_static_dep')
|
||||
```
|
||||
|
||||
To validate changes to meson.build
|
||||
```bash
|
||||
$ python3 meson.py build
|
||||
$ ninja -C build/
|
||||
```
|
||||
|
||||
To install headers, libs and pkgconfig
|
||||
```bash
|
||||
$ cd build
|
||||
$ ninja install
|
||||
```
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
MAP_FD, 0)
|
||||
|
||||
#define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
|
||||
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_FD, 0, 0, \
|
||||
BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_VALUE, 0, 0, \
|
||||
MAP_FD, VALUE_OFF)
|
||||
|
||||
#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
|
||||
|
||||
@@ -106,6 +106,7 @@ enum bpf_cmd {
|
||||
BPF_TASK_FD_QUERY,
|
||||
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
||||
BPF_MAP_FREEZE,
|
||||
BPF_BTF_GET_NEXT_ID,
|
||||
};
|
||||
|
||||
enum bpf_map_type {
|
||||
@@ -134,6 +135,7 @@ enum bpf_map_type {
|
||||
BPF_MAP_TYPE_QUEUE,
|
||||
BPF_MAP_TYPE_STACK,
|
||||
BPF_MAP_TYPE_SK_STORAGE,
|
||||
BPF_MAP_TYPE_DEVMAP_HASH,
|
||||
};
|
||||
|
||||
/* Note that tracing related programs such as
|
||||
@@ -283,6 +285,9 @@ enum bpf_attach_type {
|
||||
*/
|
||||
#define BPF_F_TEST_RND_HI32 (1U << 2)
|
||||
|
||||
/* The verifier internal test flag. Behavior is undefined */
|
||||
#define BPF_F_TEST_STATE_FREQ (1U << 3)
|
||||
|
||||
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
||||
* two extensions:
|
||||
*
|
||||
@@ -336,6 +341,9 @@ enum bpf_attach_type {
|
||||
#define BPF_F_RDONLY_PROG (1U << 7)
|
||||
#define BPF_F_WRONLY_PROG (1U << 8)
|
||||
|
||||
/* Clone map from listener for newly accepted socket */
|
||||
#define BPF_F_CLONE (1U << 9)
|
||||
|
||||
/* flags for BPF_PROG_QUERY */
|
||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||
|
||||
@@ -575,6 +583,8 @@ union bpf_attr {
|
||||
* limited to five).
|
||||
*
|
||||
* Each time the helper is called, it appends a line to the trace.
|
||||
* Lines are discarded while *\/sys/kernel/debug/tracing/trace* is
|
||||
* open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this.
|
||||
* The format of the trace is customizable, and the exact output
|
||||
* one will get depends on the options set in
|
||||
* *\/sys/kernel/debug/tracing/trace_options* (see also the
|
||||
@@ -1013,7 +1023,7 @@ union bpf_attr {
|
||||
* The realm of the route for the packet associated to *skb*, or 0
|
||||
* if none was found.
|
||||
*
|
||||
* int bpf_perf_event_output(struct pt_reg *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
|
||||
* int bpf_perf_event_output(struct pt_regs *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
|
||||
@@ -1075,7 +1085,7 @@ union bpf_attr {
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_get_stackid(struct pt_reg *ctx, struct bpf_map *map, u64 flags)
|
||||
* int bpf_get_stackid(struct pt_regs *ctx, struct bpf_map *map, u64 flags)
|
||||
* Description
|
||||
* Walk a user or a kernel stack and return its id. To achieve
|
||||
* this, the helper needs *ctx*, which is a pointer to the context
|
||||
@@ -1466,8 +1476,8 @@ union bpf_attr {
|
||||
* If no cookie has been set yet, generate a new cookie. Once
|
||||
* generated, the socket cookie remains stable for the life of the
|
||||
* socket. This helper can be useful for monitoring per socket
|
||||
* networking traffic statistics as it provides a unique socket
|
||||
* identifier per namespace.
|
||||
* networking traffic statistics as it provides a global socket
|
||||
* identifier that can be assumed unique.
|
||||
* Return
|
||||
* A 8-byte long non-decreasing number on success, or 0 if the
|
||||
* socket field is missing inside *skb*.
|
||||
@@ -1571,8 +1581,11 @@ union bpf_attr {
|
||||
* but this is only implemented for native XDP (with driver
|
||||
* support) as of this writing).
|
||||
*
|
||||
* All values for *flags* are reserved for future usage, and must
|
||||
* be left at zero.
|
||||
* The lower two bits of *flags* are used as the return code if
|
||||
* the map lookup fails. This is so that the return value can be
|
||||
* one of the XDP program return codes up to XDP_TX, as chosen by
|
||||
* the caller. Any higher bits in the *flags* argument must be
|
||||
* unset.
|
||||
*
|
||||
* When used to redirect packets to net devices, this helper
|
||||
* provides a high performance increase over **bpf_redirect**\ ().
|
||||
@@ -1721,7 +1734,7 @@ union bpf_attr {
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_override_return(struct pt_reg *regs, u64 rc)
|
||||
* int bpf_override_return(struct pt_regs *regs, u64 rc)
|
||||
* Description
|
||||
* Used for error injection, this helper uses kprobes to override
|
||||
* the return value of the probed function, and to set it to *rc*.
|
||||
@@ -2710,6 +2723,33 @@ union bpf_attr {
|
||||
* **-EPERM** if no permission to send the *sig*.
|
||||
*
|
||||
* **-EAGAIN** if bpf program can try again.
|
||||
*
|
||||
* s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
|
||||
* Description
|
||||
* Try to issue a SYN cookie for the packet with corresponding
|
||||
* IP/TCP headers, *iph* and *th*, on the listening socket in *sk*.
|
||||
*
|
||||
* *iph* points to the start of the IPv4 or IPv6 header, while
|
||||
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
|
||||
* **sizeof**\ (**struct ip6hdr**).
|
||||
*
|
||||
* *th* points to the start of the TCP header, while *th_len*
|
||||
* contains the length of the TCP header.
|
||||
*
|
||||
* Return
|
||||
* On success, lower 32 bits hold the generated SYN cookie in
|
||||
* followed by 16 bits which hold the MSS value for that cookie,
|
||||
* and the top 16 bits are unused.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EINVAL** SYN cookie cannot be issued due to error
|
||||
*
|
||||
* **-ENOENT** SYN cookie should not be issued (no SYN flood)
|
||||
*
|
||||
* **-EOPNOTSUPP** kernel configuration does not enable SYN cookies
|
||||
*
|
||||
* **-EPROTONOSUPPORT** IP packet version is not 4 or 6
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -2821,7 +2861,8 @@ union bpf_attr {
|
||||
FN(strtoul), \
|
||||
FN(sk_storage_get), \
|
||||
FN(sk_storage_delete), \
|
||||
FN(send_signal),
|
||||
FN(send_signal), \
|
||||
FN(tcp_gen_syncookie),
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
* function eBPF program intends to call
|
||||
@@ -3504,6 +3545,10 @@ 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)
|
||||
|
||||
struct bpf_flow_keys {
|
||||
__u16 nhoff;
|
||||
__u16 thoff;
|
||||
@@ -3525,6 +3570,8 @@ struct bpf_flow_keys {
|
||||
__u32 ipv6_dst[4]; /* in6_addr; network order */
|
||||
};
|
||||
};
|
||||
__u32 flags;
|
||||
__be32 flow_label;
|
||||
};
|
||||
|
||||
struct bpf_func_info {
|
||||
|
||||
@@ -695,6 +695,7 @@ enum {
|
||||
IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
|
||||
IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
|
||||
IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
|
||||
IFLA_VF_BROADCAST, /* VF broadcast */
|
||||
__IFLA_VF_MAX,
|
||||
};
|
||||
|
||||
@@ -705,6 +706,10 @@ struct ifla_vf_mac {
|
||||
__u8 mac[32]; /* MAX_ADDR_LEN */
|
||||
};
|
||||
|
||||
struct ifla_vf_broadcast {
|
||||
__u8 broadcast[32];
|
||||
};
|
||||
|
||||
struct ifla_vf_vlan {
|
||||
__u32 vf;
|
||||
__u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
#define XDP_SHARED_UMEM (1 << 0)
|
||||
#define XDP_COPY (1 << 1) /* Force copy-mode */
|
||||
#define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
|
||||
/* If this option is set, the driver might go sleep and in that case
|
||||
* the XDP_RING_NEED_WAKEUP flag in the fill and/or Tx rings will be
|
||||
* set. If it is set, the application need to explicitly wake up the
|
||||
* driver with a poll() (Rx and Tx) or sendto() (Tx only). If you are
|
||||
* running the driver and the application on the same core, you should
|
||||
* use this option so that the kernel will yield to the user space
|
||||
* application.
|
||||
*/
|
||||
#define XDP_USE_NEED_WAKEUP (1 << 3)
|
||||
|
||||
/* Flags for xsk_umem_config flags */
|
||||
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
|
||||
|
||||
struct sockaddr_xdp {
|
||||
__u16 sxdp_family;
|
||||
@@ -25,10 +37,14 @@ struct sockaddr_xdp {
|
||||
__u32 sxdp_shared_umem_fd;
|
||||
};
|
||||
|
||||
/* XDP_RING flags */
|
||||
#define XDP_RING_NEED_WAKEUP (1 << 0)
|
||||
|
||||
struct xdp_ring_offset {
|
||||
__u64 producer;
|
||||
__u64 consumer;
|
||||
__u64 desc;
|
||||
__u64 flags;
|
||||
};
|
||||
|
||||
struct xdp_mmap_offsets {
|
||||
@@ -53,6 +69,7 @@ struct xdp_umem_reg {
|
||||
__u64 len; /* Length of packet data area */
|
||||
__u32 chunk_size;
|
||||
__u32 headroom;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct xdp_statistics {
|
||||
@@ -74,6 +91,11 @@ struct xdp_options {
|
||||
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
|
||||
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
|
||||
|
||||
/* Masks for unaligned chunks mode */
|
||||
#define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
|
||||
#define XSK_UNALIGNED_BUF_ADDR_MASK \
|
||||
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
|
||||
|
||||
/* Rx/Tx descriptor */
|
||||
struct xdp_desc {
|
||||
__u64 addr;
|
||||
|
||||
95
meson.build
95
meson.build
@@ -1,95 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
|
||||
project('libbpf', 'c',
|
||||
version : '0.0.3',
|
||||
license : 'LGPL-2.1 OR BSD-2-Clause',
|
||||
default_options : [
|
||||
'prefix=/usr',
|
||||
],
|
||||
meson_version : '>= 0.46',
|
||||
)
|
||||
|
||||
patchlevel = meson.project_version().split('.')[1]
|
||||
|
||||
libbpf_source_dir = './'
|
||||
|
||||
libbpf_sources = files(run_command('find',
|
||||
[
|
||||
'@0@/src'.format(libbpf_source_dir),
|
||||
'-type',
|
||||
'f',
|
||||
'-name',
|
||||
'*.[h|c]']).stdout().split())
|
||||
|
||||
libbpf_headers = files(
|
||||
join_paths(libbpf_source_dir, 'src/bpf.h'),
|
||||
join_paths(libbpf_source_dir, 'src/btf.h'),
|
||||
join_paths(libbpf_source_dir, 'src/libbpf.h'))
|
||||
|
||||
feature_rellocarray = run_command(join_paths(libbpf_source_dir, 'scripts/check-reallocarray.sh'))
|
||||
|
||||
libbpf_c_args = ['-g',
|
||||
'-O2',
|
||||
'-Werror',
|
||||
'-Wall',
|
||||
]
|
||||
|
||||
if feature_rellocarray.stdout().strip() != ''
|
||||
libbpf_c_args += '-DCOMPAT_NEED_REALLOCARRAY'
|
||||
endif
|
||||
|
||||
# bpf_includes are required to include bpf.h, btf.h, libbpf.h
|
||||
bpf_includes = include_directories(
|
||||
join_paths(libbpf_source_dir, 'src'))
|
||||
|
||||
libbpf_includes = include_directories(
|
||||
join_paths(libbpf_source_dir, 'include'),
|
||||
join_paths(libbpf_source_dir, 'include/uapi'))
|
||||
|
||||
libelf = dependency('libelf')
|
||||
libelf = dependency('libelf', required: false)
|
||||
if not libelf.found()
|
||||
libelf = cc.find_library('elf', required: true)
|
||||
endif
|
||||
|
||||
deps = [libelf]
|
||||
|
||||
libbpf_static = static_library(
|
||||
'bpf',
|
||||
libbpf_sources,
|
||||
c_args : libbpf_c_args,
|
||||
dependencies : deps,
|
||||
include_directories : libbpf_includes,
|
||||
install : true)
|
||||
|
||||
libbpf_static_dep = declare_dependency(link_with : libbpf_static)
|
||||
|
||||
libbpf_map_source_path = join_paths(libbpf_source_dir, 'src/libbpf.map')
|
||||
libbpf_map_abs_path = join_paths(meson.current_source_dir(), libbpf_map_source_path)
|
||||
|
||||
libbpf_c_args += ['-fPIC', '-fvisibility=hidden']
|
||||
|
||||
libbpf_link_args = ['-Wl,--version-script=@0@'.format(libbpf_map_abs_path)]
|
||||
|
||||
libbpf_shared = shared_library(
|
||||
'bpf',
|
||||
libbpf_sources,
|
||||
c_args : libbpf_c_args,
|
||||
dependencies : deps,
|
||||
include_directories : libbpf_includes,
|
||||
install : true,
|
||||
link_args : libbpf_link_args,
|
||||
link_depends : libbpf_map_source_path,
|
||||
soversion : patchlevel,
|
||||
version : meson.project_version())
|
||||
|
||||
libbpf_shared_dep = declare_dependency(link_with : libbpf_shared)
|
||||
|
||||
install_headers(libbpf_headers, subdir : 'bpf')
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(
|
||||
name: meson.project_name(),
|
||||
version: meson.project_version(),
|
||||
libraries: libbpf_shared,
|
||||
requires_private: ['libelf'],
|
||||
description: '''BPF library''')
|
||||
@@ -1,40 +1,210 @@
|
||||
#!/bin/bash
|
||||
|
||||
usage () {
|
||||
echo "USAGE: ./sync-kernel.sh <kernel-repo> <libbpf-repo> [<baseline-commit>]"
|
||||
echo ""
|
||||
echo "If <baseline-commit> is not specified, it's read from <libbpf-repo>/CHECKPOINT-COMMIT"
|
||||
exit 1
|
||||
echo "USAGE: ./sync-kernel.sh <libbpf-repo> <kernel-repo> <bpf-branch>"
|
||||
echo ""
|
||||
echo "Set BPF_NEXT_BASELINE to override bpf-next tree commit, otherwise read from <libbpf-repo>/CHECKPOINT-COMMIT."
|
||||
echo "Set BPF_BASELINE to override bpf tree commit, otherwise read from <libbpf-repo>/BPF-CHECKPOINT-COMMIT."
|
||||
echo "Set MANUAL_MODE to 1 to manually control every cherry-picked commits."
|
||||
echo "Set IGNORE_CONSISTENCY to 1 to ignore failed contents consistency check."
|
||||
exit 1
|
||||
}
|
||||
|
||||
LINUX_REPO=${1-""}
|
||||
LIBBPF_REPO=${2-""}
|
||||
|
||||
if [ -z "${LINUX_REPO}" ]; then
|
||||
usage
|
||||
fi
|
||||
if [ -z "${LIBBPF_REPO}" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
set -eu
|
||||
|
||||
WORKDIR=$(pwd)
|
||||
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
||||
LIBBPF_REPO=${1-""}
|
||||
LINUX_REPO=${2-""}
|
||||
BPF_BRANCH=${3-""}
|
||||
BASELINE_COMMIT=${BPF_NEXT_BASELINE:-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||
BPF_BASELINE_COMMIT=${BPF_BASELINE:-$(cat ${LIBBPF_REPO}/BPF-CHECKPOINT-COMMIT)}
|
||||
|
||||
echo "WORKDIR: ${WORKDIR}"
|
||||
echo "LINUX REPO: ${LINUX_REPO}"
|
||||
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
||||
if [ -z "${LIBBPF_REPO}" ] || [ -z "${LINUX_REPO}" ] || [ -z "${BPF_BRANCH}" ]; then
|
||||
echo "Error: libbpf or linux repos are not specified"
|
||||
usage
|
||||
fi
|
||||
if [ -z "${BPF_BRANCH}" ]; then
|
||||
echo "Error: linux's bpf tree branch is not specified"
|
||||
usage
|
||||
fi
|
||||
if [ -z "${BASELINE_COMMIT}" ] || [ -z "${BPF_BASELINE_COMMIT}" ]; then
|
||||
echo "Error: bpf or bpf-next baseline commits are not provided"
|
||||
usage
|
||||
fi
|
||||
|
||||
SUFFIX=$(date --utc +%Y-%m-%dT%H-%M-%S.%3NZ)
|
||||
BASELINE_COMMIT=${3-$(cat ${LIBBPF_REPO}/CHECKPOINT-COMMIT)}
|
||||
WORKDIR=$(pwd)
|
||||
TMP_DIR=$(mktemp -d)
|
||||
|
||||
trap "cd ${WORKDIR}; exit" INT TERM EXIT
|
||||
|
||||
declare -A PATH_MAP
|
||||
PATH_MAP=( \
|
||||
[tools/lib/bpf]=src \
|
||||
[tools/include/uapi/linux/bpf_common.h]=include/uapi/linux/bpf_common.h \
|
||||
[tools/include/uapi/linux/bpf.h]=include/uapi/linux/bpf.h \
|
||||
[tools/include/uapi/linux/btf.h]=include/uapi/linux/btf.h \
|
||||
[tools/include/uapi/linux/if_link.h]=include/uapi/linux/if_link.h \
|
||||
[tools/include/uapi/linux/if_xdp.h]=include/uapi/linux/if_xdp.h \
|
||||
[tools/include/uapi/linux/netlink.h]=include/uapi/linux/netlink.h \
|
||||
[tools/include/tools/libc_compat.h]=include/tools/libc_compat.h \
|
||||
)
|
||||
|
||||
LIBBPF_PATHS="${!PATH_MAP[@]}"
|
||||
LIBBPF_VIEW_PATHS="${PATH_MAP[@]}"
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf.cpp|\.gitignore)$'
|
||||
|
||||
LIBBPF_TREE_FILTER="mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && "$'\\\n'
|
||||
for p in "${!PATH_MAP[@]}"; do
|
||||
LIBBPF_TREE_FILTER+="git mv -kf ${p} __libbpf/${PATH_MAP[${p}]} && "$'\\\n'
|
||||
done
|
||||
LIBBPF_TREE_FILTER+="git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.cpp,.gitignore} >/dev/null"
|
||||
|
||||
cd_to()
|
||||
{
|
||||
cd ${WORKDIR} && cd "$1"
|
||||
}
|
||||
|
||||
# Output brief single-line commit description
|
||||
# $1 - commit ref
|
||||
commit_desc()
|
||||
{
|
||||
git log -n1 --pretty='%h ("%s")' $1
|
||||
}
|
||||
|
||||
# Create commit single-line signature, which consists of:
|
||||
# - full commit hash
|
||||
# - author date in ISO8601 format
|
||||
# - full commit body with newlines replaced with vertical bars (|)
|
||||
# - shortstat appended at the end
|
||||
# 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
|
||||
commit_signature()
|
||||
{
|
||||
git log -n1 --pretty='("%s")|%aI|%b' --shortstat $1 | tr '\n' '|'
|
||||
}
|
||||
|
||||
# Validate there are no non-empty merges (we can't handle them)
|
||||
# $1 - baseline tag
|
||||
# $2 - tip tag
|
||||
validate_merges()
|
||||
{
|
||||
local baseline_tag=$1
|
||||
local tip_tag=$2
|
||||
local new_merges
|
||||
local merge_change_cnt
|
||||
local ignore_merge_resolutions
|
||||
local desc
|
||||
|
||||
new_merges=$(git rev-list --merges --topo-order --reverse ${baseline_tag}..${tip_tag} ${LIBBPF_PATHS[@]})
|
||||
for new_merge in ${new_merges}; do
|
||||
desc=$(commit_desc ${new_merge})
|
||||
echo "MERGE: ${desc}"
|
||||
merge_change_cnt=$(git show --format='' ${new_merge} | wc -l)
|
||||
if ((${merge_change_cnt} > 0)); then
|
||||
read -p "Merge '${desc}' is non-empty, which will cause conflicts! Do you want to proceed? [y/N]: " ignore_merge_resolutions
|
||||
case "${ignore_merge_resolutions}" in
|
||||
"y" | "Y")
|
||||
echo "Skipping '${desc}'..."
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
exit 3
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Cherry-pick commits touching libbpf-related files
|
||||
# $1 - baseline_tag
|
||||
# $2 - tip_tag
|
||||
cherry_pick_commits()
|
||||
{
|
||||
local manual_mode=${MANUAL_MODE:-0}
|
||||
local baseline_tag=$1
|
||||
local tip_tag=$2
|
||||
local new_commits
|
||||
local signature
|
||||
local should_skip
|
||||
local synced_cnt
|
||||
local manual_check
|
||||
local libbpf_conflict_cnt
|
||||
local desc
|
||||
|
||||
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})"
|
||||
synced_cnt=$(grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | wc -l)
|
||||
manual_check=0
|
||||
if ((${synced_cnt} > 0)); then
|
||||
# commit with the same subject is already in libbpf, but it's
|
||||
# not 100% the same commit, so check with user
|
||||
echo "Commit '${desc}' is synced into libbpf as:"
|
||||
grep -F "${signature}" ${TMP_DIR}/libbpf_commits.txt | \
|
||||
cut -d'|' -f1 | sed -e 's/^/- /'
|
||||
if ((${manual_mode} != 1 && ${synced_cnt} == 1)); then
|
||||
echo "Skipping '${desc}' due to unique match..."
|
||||
continue
|
||||
fi
|
||||
if ((${synced_cnt} > 1)); then
|
||||
echo "'${desc} matches multiple commits, please, double-check!"
|
||||
manual_check=1
|
||||
fi
|
||||
fi
|
||||
if ((${manual_mode} == 1 || ${manual_check} == 1)); then
|
||||
read -p "Do you want to skip '${desc}'? [y/N]: " should_skip
|
||||
case "${should_skip}" in
|
||||
"y" | "Y")
|
||||
echo "Skipping '${desc}'..."
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# commit hasn't been synced into libbpf yet
|
||||
echo "Picking '${desc}'..."
|
||||
if ! git cherry-pick ${new_commit} &>/dev/null; then
|
||||
echo "Warning! Cherry-picking '${desc} failed, checking if it's non-libbpf files causing problems..."
|
||||
libbpf_conflict_cnt=$(git diff --name-only --diff-filter=U -- ${LIBBPF_PATHS[@]} | wc -l)
|
||||
conflict_cnt=$(git diff --name-only | wc -l)
|
||||
|
||||
if ((${libbpf_conflict_cnt} == 0)); then
|
||||
echo "Looks like only non-libbpf files have conflicts, ignoring..."
|
||||
if ((${conflict_cnt} == 0)); then
|
||||
echo "Empty cherry-pick, skipping it..."
|
||||
git cherry-pick --abort
|
||||
continue
|
||||
fi
|
||||
|
||||
git add .
|
||||
# GIT_EDITOR=true to avoid editor popping up to edit commit message
|
||||
if ! GIT_EDITOR=true git cherry-pick --continue &>/dev/null; then
|
||||
echo "Error! That still failed! Please resolve manually."
|
||||
else
|
||||
echo "Success! All cherry-pick conflicts were resolved for '${desc}'!"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
read -p "Error! Cherry-picking '${desc}' failed, please fix manually and press <return> to proceed..."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
cd_to ${LIBBPF_REPO}
|
||||
echo "Dumping existing libbpf commit signatures..."
|
||||
for h in $(git log --pretty='%h' -n500); do
|
||||
echo $h "$(commit_signature $h)" >> ${TMP_DIR}/libbpf_commits.txt
|
||||
done
|
||||
|
||||
# Use current kernel repo HEAD as a source of patches
|
||||
cd ${LINUX_REPO}
|
||||
cd_to ${LINUX_REPO}
|
||||
TIP_SYM_REF=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
|
||||
TIP_COMMIT=$(git rev-parse HEAD)
|
||||
BPF_TIP_COMMIT=$(git rev-parse ${BPF_BRANCH})
|
||||
BASELINE_TAG=libbpf-baseline-${SUFFIX}
|
||||
TIP_TAG=libbpf-tip-${SUFFIX}
|
||||
BPF_BASELINE_TAG=libbpf-bpf-baseline-${SUFFIX}
|
||||
BPF_TIP_TAG=libbpf-bpf-tip-${SUFFIX}
|
||||
VIEW_TAG=libbpf-view-${SUFFIX}
|
||||
LIBBPF_SYNC_TAG=libbpf-sync-${SUFFIX}
|
||||
|
||||
@@ -43,75 +213,41 @@ SQUASH_BASE_TAG=libbpf-squash-base-${SUFFIX}
|
||||
SQUASH_TIP_TAG=libbpf-squash-tip-${SUFFIX}
|
||||
SQUASH_COMMIT=$(git commit-tree ${BASELINE_COMMIT}^{tree} -m "BASELINE SQUASH ${BASELINE_COMMIT}")
|
||||
|
||||
echo "SUFFIX: ${SUFFIX}"
|
||||
echo "BASELINE COMMIT: $(git log --pretty=oneline --no-walk ${BASELINE_COMMIT})"
|
||||
echo "TIP COMMIT: $(git log --pretty=oneline --no-walk ${TIP_COMMIT})"
|
||||
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
||||
echo "BASELINE TAG: ${BASELINE_TAG}"
|
||||
echo "TIP TAG: ${TIP_TAG}"
|
||||
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
||||
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
||||
echo "VIEW TAG: ${VIEW_TAG}"
|
||||
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
echo "TEMP DIR: ${TMP_DIR}"
|
||||
echo "PATCHES+COVER: ${TMP_DIR}/patches"
|
||||
echo "PATCHSET: ${TMP_DIR}/patchset.patch"
|
||||
echo "WORKDIR: ${WORKDIR}"
|
||||
echo "LINUX REPO: ${LINUX_REPO}"
|
||||
echo "LIBBPF REPO: ${LIBBPF_REPO}"
|
||||
echo "TEMP DIR: ${TMP_DIR}"
|
||||
echo "SUFFIX: ${SUFFIX}"
|
||||
echo "BASE COMMIT: '$(commit_desc ${BASELINE_COMMIT})'"
|
||||
echo "TIP COMMIT: '$(commit_desc ${TIP_COMMIT})'"
|
||||
echo "BPF BASE COMMIT: '$(commit_desc ${BPF_BASELINE_COMMIT})'"
|
||||
echo "BPF TIP COMMIT: '$(commit_desc ${BPF_TIP_COMMIT})'"
|
||||
echo "SQUASH COMMIT: ${SQUASH_COMMIT}"
|
||||
echo "BASELINE TAG: ${BASELINE_TAG}"
|
||||
echo "TIP TAG: ${TIP_TAG}"
|
||||
echo "BPF BASELINE TAG: ${BPF_BASELINE_TAG}"
|
||||
echo "BPF TIP TAG: ${BPF_TIP_TAG}"
|
||||
echo "SQUASH BASE TAG: ${SQUASH_BASE_TAG}"
|
||||
echo "SQUASH TIP TAG: ${SQUASH_TIP_TAG}"
|
||||
echo "VIEW TAG: ${VIEW_TAG}"
|
||||
echo "LIBBPF SYNC TAG: ${LIBBPF_SYNC_TAG}"
|
||||
echo "PATCHES: ${TMP_DIR}/patches"
|
||||
|
||||
git branch ${BASELINE_TAG} ${BASELINE_COMMIT}
|
||||
git branch ${TIP_TAG} ${TIP_COMMIT}
|
||||
git branch ${BPF_BASELINE_TAG} ${BPF_BASELINE_COMMIT}
|
||||
git branch ${BPF_TIP_TAG} ${BPF_TIP_COMMIT}
|
||||
git branch ${SQUASH_BASE_TAG} ${SQUASH_COMMIT}
|
||||
git checkout -b ${SQUASH_TIP_TAG} ${SQUASH_COMMIT}
|
||||
|
||||
# Validate there are no non-empty merges in bpf-next and bpf trees
|
||||
validate_merges ${BASELINE_TAG} ${TIP_TAG}
|
||||
validate_merges ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||
|
||||
# Cherry-pick new commits onto squashed baseline commit
|
||||
LIBBPF_PATHS=(tools/lib/bpf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} tools/include/tools/libc_compat.h)
|
||||
cherry_pick_commits ${BASELINE_TAG} ${TIP_TAG}
|
||||
cherry_pick_commits ${BPF_BASELINE_TAG} ${BPF_TIP_TAG}
|
||||
|
||||
LIBBPF_NEW_MERGES=$(git rev-list --merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
||||
for LIBBPF_NEW_MERGE in ${LIBBPF_NEW_MERGES}; do
|
||||
printf "MERGE:\t" && git log --oneline -n1 ${LIBBPF_NEW_MERGE}
|
||||
MERGE_CHANGES=$(git log --format='' -n1 ${LIBBPF_NEW_MERGE} | wc -l)
|
||||
if ((${MERGE_CHANGES} > 0)); then
|
||||
echo "Merge is non empty, aborting!.."
|
||||
exit 3
|
||||
fi
|
||||
done
|
||||
|
||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
||||
git log --oneline -n500 > ${TMP_DIR}/libbpf_commits.txt
|
||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
||||
|
||||
LIBBPF_NEW_COMMITS=$(git rev-list --no-merges --topo-order --reverse ${BASELINE_TAG}..${TIP_TAG} ${LIBBPF_PATHS[@]})
|
||||
for LIBBPF_NEW_COMMIT in ${LIBBPF_NEW_COMMITS}; do
|
||||
echo "Checking commit '${LIBBPF_NEW_COMMIT}'"
|
||||
SYNCED_COMMITS=$(grep -F "$(git log -n1 --pretty=format:%s ${LIBBPF_NEW_COMMIT})" ${TMP_DIR}/libbpf_commits.txt || echo "")
|
||||
if [ -n "${SYNCED_COMMITS}" ]; then
|
||||
# commit with the same subject is already in libbpf, but it's not 100% the same commit, so check with user
|
||||
echo "Commit '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})' appears to be already synced into libbpf..."
|
||||
echo "Corresponding libbpf commit(s):"
|
||||
echo "${SYNCED_COMMITS}"
|
||||
read -p "Do you want to skip it? [y/N]: " SHOULD_SKIP
|
||||
case "${SHOULD_SKIP}" in
|
||||
"y" | "Y")
|
||||
echo "Skipping '$(git log -n1 --oneline ${LIBBPF_NEW_COMMIT})'..."
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# commit hasn't been synced into libbpf yet
|
||||
if ! git cherry-pick ${LIBBPF_NEW_COMMIT}; then
|
||||
read -p "Cherry-picking '$(git log --oneline -n1 ${LIBBPF_NEW_COMMIT})' failed, please fix manually and press <return> to proceed..."
|
||||
fi
|
||||
done
|
||||
|
||||
LIBBPF_TREE_FILTER=' \
|
||||
mkdir -p __libbpf/include/uapi/linux __libbpf/include/tools && \
|
||||
git mv -kf tools/lib/bpf __libbpf/src && \
|
||||
git mv -kf tools/include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} \
|
||||
__libbpf/include/uapi/linux && \
|
||||
git mv -kf tools/include/tools/libc_compat.h __libbpf/include/tools && \
|
||||
git rm --ignore-unmatch -f __libbpf/src/{Makefile,Build,test_libbpf.cpp,.gitignore} \
|
||||
'
|
||||
# Move all libbpf files into __libbpf directory.
|
||||
git filter-branch --prune-empty -f --tree-filter "${LIBBPF_TREE_FILTER}" ${SQUASH_TIP_TAG} ${SQUASH_BASE_TAG}
|
||||
# Make __libbpf a new root directory
|
||||
@@ -126,59 +262,76 @@ fi
|
||||
|
||||
# Exclude baseline commit and generate nice cover letter with summary
|
||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --cover-letter -o ${TMP_DIR}/patches
|
||||
# Now generate single-file patchset w/o cover to apply on top of libbpf repo
|
||||
git format-patch ${SQUASH_BASE_TAG}..${SQUASH_TIP_TAG} --stdout > ${TMP_DIR}/patchset.patch
|
||||
|
||||
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
||||
# Now is time to re-apply libbpf-related linux patches to libbpf repo
|
||||
cd_to ${LIBBPF_REPO}
|
||||
git checkout -b ${LIBBPF_SYNC_TAG}
|
||||
git am --committer-date-is-author-date ${TMP_DIR}/patchset.patch
|
||||
|
||||
for patch in $(ls -1 ${TMP_DIR}/patches | tail -n +2); do
|
||||
if ! git am --committer-date-is-author-date "${TMP_DIR}/patches/${patch}"; then
|
||||
read -p "Applying ${TMP_DIR}/patches/${patch} failed, please resolve manually and press <return> to proceed..."
|
||||
fi
|
||||
done
|
||||
|
||||
# Use generated cover-letter as a template for "sync commit" with
|
||||
# baseline and checkpoint commits from kernel repo (and leave summary
|
||||
# from cover letter intact, of course)
|
||||
echo ${TIP_COMMIT} > CHECKPOINT-COMMIT && \
|
||||
echo ${BPF_TIP_COMMIT} > BPF-CHECKPOINT-COMMIT && \
|
||||
git add CHECKPOINT-COMMIT && \
|
||||
git add BPF-CHECKPOINT-COMMIT && \
|
||||
awk '/\*\*\* BLURB HERE \*\*\*/ {p=1} p' ${TMP_DIR}/patches/0000-cover-letter.patch | \
|
||||
sed "s/\*\*\* BLURB HERE \*\*\*/\
|
||||
sync: latest libbpf changes from kernel\n\
|
||||
\n\
|
||||
Syncing latest libbpf commits from kernel repository.\n\
|
||||
Baseline commit: ${BASELINE_COMMIT}\n\
|
||||
Checkpoint commit: ${TIP_COMMIT}/" | \
|
||||
Baseline bpf-next commit: ${BASELINE_COMMIT}\n\
|
||||
Checkpoint bpf-next commit: ${TIP_COMMIT}\n\
|
||||
Baseline bpf commit: ${BPF_BASELINE_COMMIT}\n\
|
||||
Checkpoint bpf commit: ${BPF_TIP_COMMIT}/" | \
|
||||
git commit --file=-
|
||||
|
||||
echo "SUCCESS! ${COMMIT_CNT} commits synced."
|
||||
|
||||
echo "Verifying Linux's and Github's libbpf state"
|
||||
LIBBPF_VIEW_PATHS=(src include/uapi/linux/{bpf_common.h,bpf.h,btf.h,if_link.h,if_xdp.h,netlink.h} include/tools/libc_compat.h)
|
||||
LIBBPF_VIEW_EXCLUDE_REGEX='^src/(Makefile|Build|test_libbpf.cpp|\.gitignore)$'
|
||||
|
||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
||||
cd_to ${LINUX_REPO}
|
||||
LINUX_ABS_DIR=$(pwd)
|
||||
git checkout -b ${VIEW_TAG} ${TIP_COMMIT}
|
||||
git filter-branch -f --tree-filter "${LIBBPF_TREE_FILTER}" ${VIEW_TAG}^..${VIEW_TAG}
|
||||
git filter-branch -f --subdirectory-filter __libbpf ${VIEW_TAG}^..${VIEW_TAG}
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} > ${TMP_DIR}/linux-view.ls
|
||||
|
||||
cd ${WORKDIR} && cd ${LIBBPF_REPO}
|
||||
cd_to ${LIBBPF_REPO}
|
||||
GITHUB_ABS_DIR=$(pwd)
|
||||
git ls-files -- ${LIBBPF_VIEW_PATHS[@]} | grep -v -E "${LIBBPF_VIEW_EXCLUDE_REGEX}" > ${TMP_DIR}/github-view.ls
|
||||
|
||||
echo "Comparing list of files..."
|
||||
diff ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||
diff -u ${TMP_DIR}/linux-view.ls ${TMP_DIR}/github-view.ls
|
||||
echo "Comparing file contents..."
|
||||
CONSISTENT=1
|
||||
for F in $(cat ${TMP_DIR}/linux-view.ls); do
|
||||
diff "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"
|
||||
if ! diff -u "${LINUX_ABS_DIR}/${F}" "${GITHUB_ABS_DIR}/${F}"; then
|
||||
echo "${LINUX_ABS_DIR}/${F} and ${GITHUB_ABS_DIR}/${F} are different!"
|
||||
CONSISTENT=0
|
||||
fi
|
||||
done
|
||||
echo "Contents appear identical!"
|
||||
if ((${CONSISTENT} == 1)); then
|
||||
echo "Great! Content is identical!"
|
||||
else
|
||||
echo "Unfortunately, there are consistency problems!"
|
||||
if ((${IGNORE_CONSISTENCY-0} != 1)); then
|
||||
exit 4
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Cleaning up..."
|
||||
rm -r ${TMP_DIR}
|
||||
cd ${WORKDIR} && cd ${LINUX_REPO}
|
||||
cd_to ${LINUX_REPO}
|
||||
git checkout ${TIP_SYM_REF}
|
||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
||||
git branch -D ${BASELINE_TAG} ${TIP_TAG} ${BPF_BASELINE_TAG} ${BPF_TIP_TAG} \
|
||||
${SQUASH_BASE_TAG} ${SQUASH_TIP_TAG} ${VIEW_TAG}
|
||||
|
||||
cd ${WORKDIR}
|
||||
cd_to .
|
||||
echo "DONE."
|
||||
|
||||
|
||||
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@@ -2,3 +2,5 @@
|
||||
*.a
|
||||
/libbpf.pc
|
||||
/libbpf.so*
|
||||
/staticobjs
|
||||
/sharedobjs
|
||||
|
||||
65
src/Makefile
65
src/Makefile
@@ -1,10 +1,9 @@
|
||||
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
VERSION = 0
|
||||
PATCHLEVEL = 0
|
||||
EXTRAVERSION = 3
|
||||
|
||||
LIBBPF_VERSION = $(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)
|
||||
LIBBPF_VERSION := $(shell \
|
||||
grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | \
|
||||
sort -rV | head -n1 | cut -d'_' -f2)
|
||||
LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
|
||||
|
||||
TOPDIR = ..
|
||||
|
||||
@@ -16,9 +15,7 @@ ifneq ($(FEATURE_REALLOCARRAY),)
|
||||
ALL_CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||
endif
|
||||
|
||||
ifndef BUILD_STATIC_ONLY
|
||||
ALL_CFLAGS += -fPIC -fvisibility=hidden
|
||||
endif
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
CFLAGS ?= -g -O2 -Werror -Wall
|
||||
ALL_CFLAGS += $(CFLAGS)
|
||||
@@ -32,22 +29,25 @@ else
|
||||
endif
|
||||
|
||||
OBJDIR ?= .
|
||||
|
||||
OBJS := $(addprefix $(OBJDIR)/,bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||
SHARED_OBJDIR := $(OBJDIR)/sharedobjs
|
||||
STATIC_OBJDIR := $(OBJDIR)/staticobjs
|
||||
OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
|
||||
nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
|
||||
btf_dump.o hashmap.o)
|
||||
btf_dump.o hashmap.o
|
||||
SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
|
||||
STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
|
||||
|
||||
LIBS := $(OBJDIR)/libbpf.a
|
||||
STATIC_LIBS := $(OBJDIR)/libbpf.a
|
||||
ifndef BUILD_STATIC_ONLY
|
||||
LIBS += $(OBJDIR)/libbpf.so \
|
||||
$(OBJDIR)/libbpf.so.$(VERSION) \
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||
SHARED_LIBS := $(OBJDIR)/libbpf.so \
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||
VERSION_SCRIPT := libbpf.map
|
||||
endif
|
||||
|
||||
HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h
|
||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,bpf.h bpf_common.h \
|
||||
btf.h)
|
||||
UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
|
||||
bpf.h bpf_common.h btf.h)
|
||||
|
||||
PC_FILE := $(OBJDIR)/libbpf.pc
|
||||
|
||||
@@ -66,21 +66,21 @@ LIBDIR ?= $(PREFIX)/$(LIBSUBDIR)
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
UAPIDIR ?= $(PREFIX)/include
|
||||
|
||||
all: $(LIBS) $(PC_FILE)
|
||||
all: $(STATIC_LIBS) $(SHARED_LIBS) $(PC_FILE)
|
||||
|
||||
$(OBJDIR)/libbpf.a: $(OBJS)
|
||||
$(OBJDIR)/libbpf.a: $(STATIC_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(VERSION)
|
||||
$(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION)
|
||||
ln -sf $(^F) $@
|
||||
|
||||
$(OBJDIR)/libbpf.so.$(VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
|
||||
ln -sf $(^F) $@
|
||||
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(OBJS)
|
||||
$(CC) -shared $(ALL_LDFLAGS) -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||
-Wl,-soname,libbpf.so.$(VERSION) \
|
||||
$^ -o $@
|
||||
$(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
|
||||
$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||
-Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
|
||||
$^ $(ALL_LDFLAGS) -o $@
|
||||
|
||||
$(OBJDIR)/libbpf.pc:
|
||||
sed -e "s|@PREFIX@|$(PREFIX)|" \
|
||||
@@ -88,9 +88,18 @@ $(OBJDIR)/libbpf.pc:
|
||||
-e "s|@VERSION@|$(LIBBPF_VERSION)|" \
|
||||
< libbpf.pc.template > $@
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
$(STATIC_OBJDIR):
|
||||
mkdir -p $(STATIC_OBJDIR)
|
||||
|
||||
$(SHARED_OBJDIR):
|
||||
mkdir -p $(SHARED_OBJDIR)
|
||||
|
||||
$(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
|
||||
$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
$(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
|
||||
$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
define do_install
|
||||
if [ ! -d '$(DESTDIR)$2' ]; then \
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
|
||||
@@ -107,7 +116,7 @@ define do_s_install
|
||||
endef
|
||||
|
||||
install: all install_headers install_pkgconfig
|
||||
$(call do_s_install,$(LIBS),$(LIBDIR))
|
||||
$(call do_s_install,$(STATIC_LIBS) $(SHARED_LIBS),$(LIBDIR))
|
||||
|
||||
install_headers:
|
||||
$(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
|
||||
@@ -121,4 +130,4 @@ install_pkgconfig: $(PC_FILE)
|
||||
$(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *.so *.so.* *.pc
|
||||
rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
|
||||
|
||||
24
src/bpf.c
24
src/bpf.c
@@ -568,7 +568,7 @@ int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
static int bpf_obj_get_next_id(__u32 start_id, __u32 *next_id, int cmd)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
int err;
|
||||
@@ -576,26 +576,26 @@ int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.start_id = start_id;
|
||||
|
||||
err = sys_bpf(BPF_PROG_GET_NEXT_ID, &attr, sizeof(attr));
|
||||
err = sys_bpf(cmd, &attr, sizeof(attr));
|
||||
if (!err)
|
||||
*next_id = attr.next_id;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
{
|
||||
return bpf_obj_get_next_id(start_id, next_id, BPF_PROG_GET_NEXT_ID);
|
||||
}
|
||||
|
||||
int bpf_map_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
int err;
|
||||
return bpf_obj_get_next_id(start_id, next_id, BPF_MAP_GET_NEXT_ID);
|
||||
}
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.start_id = start_id;
|
||||
|
||||
err = sys_bpf(BPF_MAP_GET_NEXT_ID, &attr, sizeof(attr));
|
||||
if (!err)
|
||||
*next_id = attr.next_id;
|
||||
|
||||
return err;
|
||||
int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id)
|
||||
{
|
||||
return bpf_obj_get_next_id(start_id, next_id, BPF_BTF_GET_NEXT_ID);
|
||||
}
|
||||
|
||||
int bpf_prog_get_fd_by_id(__u32 id)
|
||||
|
||||
@@ -156,6 +156,7 @@ LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
||||
__u32 *retval, __u32 *duration);
|
||||
LIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
|
||||
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
|
||||
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
|
||||
|
||||
255
src/btf.c
255
src/btf.c
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
/* Copyright (c) 2018 Facebook */
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -19,13 +20,6 @@
|
||||
#define BTF_MAX_NR_TYPES 0x7fffffff
|
||||
#define BTF_MAX_STR_OFFSET 0x7fffffff
|
||||
|
||||
#define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \
|
||||
((k) == BTF_KIND_VOLATILE) || \
|
||||
((k) == BTF_KIND_CONST) || \
|
||||
((k) == BTF_KIND_RESTRICT))
|
||||
|
||||
#define IS_VAR(k) ((k) == BTF_KIND_VAR)
|
||||
|
||||
static struct btf_type btf_void;
|
||||
|
||||
struct btf {
|
||||
@@ -42,47 +36,6 @@ struct btf {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct btf_ext_info {
|
||||
/*
|
||||
* info points to the individual info section (e.g. func_info and
|
||||
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
||||
*/
|
||||
void *info;
|
||||
__u32 rec_size;
|
||||
__u32 len;
|
||||
};
|
||||
|
||||
struct btf_ext {
|
||||
union {
|
||||
struct btf_ext_header *hdr;
|
||||
void *data;
|
||||
};
|
||||
struct btf_ext_info func_info;
|
||||
struct btf_ext_info line_info;
|
||||
__u32 data_size;
|
||||
};
|
||||
|
||||
struct btf_ext_info_sec {
|
||||
__u32 sec_name_off;
|
||||
__u32 num_info;
|
||||
/* Followed by num_info * record_size number of bytes */
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
/* The minimum bpf_func_info checked by the loader */
|
||||
struct bpf_func_info_min {
|
||||
__u32 insn_off;
|
||||
__u32 type_id;
|
||||
};
|
||||
|
||||
/* The minimum bpf_line_info checked by the loader */
|
||||
struct bpf_line_info_min {
|
||||
__u32 insn_off;
|
||||
__u32 file_name_off;
|
||||
__u32 line_off;
|
||||
__u32 line_col;
|
||||
};
|
||||
|
||||
static inline __u64 ptr_to_u64(const void *ptr)
|
||||
{
|
||||
return (__u64) (unsigned long) ptr;
|
||||
@@ -192,9 +145,9 @@ static int btf_parse_str_sec(struct btf *btf)
|
||||
static int btf_type_size(struct btf_type *t)
|
||||
{
|
||||
int base_size = sizeof(struct btf_type);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_VOLATILE:
|
||||
@@ -219,7 +172,7 @@ static int btf_type_size(struct btf_type *t)
|
||||
case BTF_KIND_DATASEC:
|
||||
return base_size + vlen * sizeof(struct btf_var_secinfo);
|
||||
default:
|
||||
pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info));
|
||||
pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -263,7 +216,7 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
|
||||
|
||||
static bool btf_type_is_void(const struct btf_type *t)
|
||||
{
|
||||
return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
|
||||
return t == &btf_void || btf_is_fwd(t);
|
||||
}
|
||||
|
||||
static bool btf_type_is_void_or_null(const struct btf_type *t)
|
||||
@@ -284,7 +237,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
||||
t = btf__type_by_id(btf, type_id);
|
||||
for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
|
||||
i++) {
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION:
|
||||
@@ -303,7 +256,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
|
||||
type_id = t->type;
|
||||
break;
|
||||
case BTF_KIND_ARRAY:
|
||||
array = (const struct btf_array *)(t + 1);
|
||||
array = btf_array(t);
|
||||
if (nelems && array->nelems > UINT32_MAX / nelems)
|
||||
return -E2BIG;
|
||||
nelems *= array->nelems;
|
||||
@@ -334,8 +287,7 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
|
||||
t = btf__type_by_id(btf, type_id);
|
||||
while (depth < MAX_RESOLVE_DEPTH &&
|
||||
!btf_type_is_void_or_null(t) &&
|
||||
(IS_MODIFIER(BTF_INFO_KIND(t->info)) ||
|
||||
IS_VAR(BTF_INFO_KIND(t->info)))) {
|
||||
(btf_is_mod(t) || btf_is_typedef(t) || btf_is_var(t))) {
|
||||
type_id = t->type;
|
||||
t = btf__type_by_id(btf, type_id);
|
||||
depth++;
|
||||
@@ -419,9 +371,9 @@ done:
|
||||
|
||||
static bool btf_check_endianness(const GElf_Ehdr *ehdr)
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return ehdr->e_ident[EI_DATA] == ELFDATA2LSB;
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
return ehdr->e_ident[EI_DATA] == ELFDATA2MSB;
|
||||
#else
|
||||
# error "Unrecognized __BYTE_ORDER__"
|
||||
@@ -554,11 +506,11 @@ static int compare_vsi_off(const void *_a, const void *_b)
|
||||
static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
||||
struct btf_type *t)
|
||||
{
|
||||
__u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info);
|
||||
__u32 size = 0, off = 0, i, vars = btf_vlen(t);
|
||||
const char *name = btf__name_by_offset(btf, t->name_off);
|
||||
const struct btf_type *t_var;
|
||||
struct btf_var_secinfo *vsi;
|
||||
struct btf_var *var;
|
||||
const struct btf_var *var;
|
||||
int ret;
|
||||
|
||||
if (!name) {
|
||||
@@ -574,12 +526,11 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
||||
|
||||
t->size = size;
|
||||
|
||||
for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1);
|
||||
i < vars; i++, vsi++) {
|
||||
for (i = 0, vsi = btf_var_secinfos(t); i < vars; i++, vsi++) {
|
||||
t_var = btf__type_by_id(btf, vsi->type);
|
||||
var = (struct btf_var *)(t_var + 1);
|
||||
var = btf_var(t_var);
|
||||
|
||||
if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) {
|
||||
if (!btf_is_var(t_var)) {
|
||||
pr_debug("Non-VAR type seen in section %s\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -595,7 +546,8 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
|
||||
|
||||
ret = bpf_object__variable_offset(obj, name, &off);
|
||||
if (ret) {
|
||||
pr_debug("No offset found in symbol table for VAR %s\n", name);
|
||||
pr_debug("No offset found in symbol table for VAR %s\n",
|
||||
name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -619,7 +571,7 @@ int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
|
||||
* is section size and global variable offset. We use
|
||||
* the info from the ELF itself for this purpose.
|
||||
*/
|
||||
if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) {
|
||||
if (btf_is_datasec(t)) {
|
||||
err = btf_fixup_datasec(obj, btf, t);
|
||||
if (err)
|
||||
break;
|
||||
@@ -774,14 +726,13 @@ int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (BTF_INFO_KIND(container_type->info) != BTF_KIND_STRUCT ||
|
||||
BTF_INFO_VLEN(container_type->info) < 2) {
|
||||
if (!btf_is_struct(container_type) || btf_vlen(container_type) < 2) {
|
||||
pr_warning("map:%s container_name:%s is an invalid container struct\n",
|
||||
map_name, container_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key = (struct btf_member *)(container_type + 1);
|
||||
key = btf_members(container_type);
|
||||
value = key + 1;
|
||||
|
||||
key_size = btf__resolve_size(btf, key->type);
|
||||
@@ -831,6 +782,9 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
|
||||
/* The start of the info sec (including the __u32 record_size). */
|
||||
void *info;
|
||||
|
||||
if (ext_sec->len == 0)
|
||||
return 0;
|
||||
|
||||
if (ext_sec->off & 0x03) {
|
||||
pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
|
||||
ext_sec->desc);
|
||||
@@ -934,11 +888,24 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
|
||||
return btf_ext_setup_info(btf_ext, ¶m);
|
||||
}
|
||||
|
||||
static int btf_ext_setup_offset_reloc(struct btf_ext *btf_ext)
|
||||
{
|
||||
struct btf_ext_sec_setup_param param = {
|
||||
.off = btf_ext->hdr->offset_reloc_off,
|
||||
.len = btf_ext->hdr->offset_reloc_len,
|
||||
.min_rec_size = sizeof(struct bpf_offset_reloc),
|
||||
.ext_info = &btf_ext->offset_reloc_info,
|
||||
.desc = "offset_reloc",
|
||||
};
|
||||
|
||||
return btf_ext_setup_info(btf_ext, ¶m);
|
||||
}
|
||||
|
||||
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
|
||||
{
|
||||
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||
|
||||
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
|
||||
if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
|
||||
data_size < hdr->hdr_len) {
|
||||
pr_debug("BTF.ext header not found");
|
||||
return -EINVAL;
|
||||
@@ -996,6 +963,9 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
||||
}
|
||||
memcpy(btf_ext->data, data, size);
|
||||
|
||||
if (btf_ext->hdr->hdr_len <
|
||||
offsetofend(struct btf_ext_header, line_info_len))
|
||||
goto done;
|
||||
err = btf_ext_setup_func_info(btf_ext);
|
||||
if (err)
|
||||
goto done;
|
||||
@@ -1004,6 +974,13 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
if (btf_ext->hdr->hdr_len <
|
||||
offsetofend(struct btf_ext_header, offset_reloc_len))
|
||||
goto done;
|
||||
err = btf_ext_setup_offset_reloc(btf_ext);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (err) {
|
||||
btf_ext__free(btf_ext);
|
||||
@@ -1440,10 +1417,9 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, struct btf_ext *btf_ext,
|
||||
d->map[0] = 0;
|
||||
for (i = 1; i <= btf->nr_types; i++) {
|
||||
struct btf_type *t = d->btf->types[i];
|
||||
__u16 kind = BTF_INFO_KIND(t->info);
|
||||
|
||||
/* VAR and DATASEC are never deduped and are self-canonical */
|
||||
if (kind == BTF_KIND_VAR || kind == BTF_KIND_DATASEC)
|
||||
if (btf_is_var(t) || btf_is_datasec(t))
|
||||
d->map[i] = i;
|
||||
else
|
||||
d->map[i] = BTF_UNPROCESSED_ID;
|
||||
@@ -1484,11 +1460,11 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
struct btf_member *m = (struct btf_member *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_member *m = btf_members(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
for (j = 0; j < vlen; j++) {
|
||||
r = fn(&m->name_off, ctx);
|
||||
@@ -1499,8 +1475,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_ENUM: {
|
||||
struct btf_enum *m = (struct btf_enum *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_enum *m = btf_enum(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
for (j = 0; j < vlen; j++) {
|
||||
r = fn(&m->name_off, ctx);
|
||||
@@ -1511,8 +1487,8 @@ static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
struct btf_param *m = (struct btf_param *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_param *m = btf_params(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
for (j = 0; j < vlen; j++) {
|
||||
r = fn(&m->name_off, ctx);
|
||||
@@ -1801,16 +1777,16 @@ static long btf_hash_enum(struct btf_type *t)
|
||||
/* Check structural equality of two ENUMs. */
|
||||
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_enum *m1, *m2;
|
||||
const struct btf_enum *m1, *m2;
|
||||
__u16 vlen;
|
||||
int i;
|
||||
|
||||
if (!btf_equal_common(t1, t2))
|
||||
return false;
|
||||
|
||||
vlen = BTF_INFO_VLEN(t1->info);
|
||||
m1 = (struct btf_enum *)(t1 + 1);
|
||||
m2 = (struct btf_enum *)(t2 + 1);
|
||||
vlen = btf_vlen(t1);
|
||||
m1 = btf_enum(t1);
|
||||
m2 = btf_enum(t2);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (m1->name_off != m2->name_off || m1->val != m2->val)
|
||||
return false;
|
||||
@@ -1822,8 +1798,7 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
|
||||
|
||||
static inline bool btf_is_enum_fwd(struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM &&
|
||||
BTF_INFO_VLEN(t->info) == 0;
|
||||
return btf_is_enum(t) && btf_vlen(t) == 0;
|
||||
}
|
||||
|
||||
static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
||||
@@ -1843,8 +1818,8 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
|
||||
*/
|
||||
static long btf_hash_struct(struct btf_type *t)
|
||||
{
|
||||
struct btf_member *member = (struct btf_member *)(t + 1);
|
||||
__u32 vlen = BTF_INFO_VLEN(t->info);
|
||||
const struct btf_member *member = btf_members(t);
|
||||
__u32 vlen = btf_vlen(t);
|
||||
long h = btf_hash_common(t);
|
||||
int i;
|
||||
|
||||
@@ -1864,16 +1839,16 @@ static long btf_hash_struct(struct btf_type *t)
|
||||
*/
|
||||
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_member *m1, *m2;
|
||||
const struct btf_member *m1, *m2;
|
||||
__u16 vlen;
|
||||
int i;
|
||||
|
||||
if (!btf_equal_common(t1, t2))
|
||||
return false;
|
||||
|
||||
vlen = BTF_INFO_VLEN(t1->info);
|
||||
m1 = (struct btf_member *)(t1 + 1);
|
||||
m2 = (struct btf_member *)(t2 + 1);
|
||||
vlen = btf_vlen(t1);
|
||||
m1 = btf_members(t1);
|
||||
m2 = btf_members(t2);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (m1->name_off != m2->name_off || m1->offset != m2->offset)
|
||||
return false;
|
||||
@@ -1890,7 +1865,7 @@ static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
|
||||
*/
|
||||
static long btf_hash_array(struct btf_type *t)
|
||||
{
|
||||
struct btf_array *info = (struct btf_array *)(t + 1);
|
||||
const struct btf_array *info = btf_array(t);
|
||||
long h = btf_hash_common(t);
|
||||
|
||||
h = hash_combine(h, info->type);
|
||||
@@ -1908,13 +1883,13 @@ static long btf_hash_array(struct btf_type *t)
|
||||
*/
|
||||
static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_array *info1, *info2;
|
||||
const struct btf_array *info1, *info2;
|
||||
|
||||
if (!btf_equal_common(t1, t2))
|
||||
return false;
|
||||
|
||||
info1 = (struct btf_array *)(t1 + 1);
|
||||
info2 = (struct btf_array *)(t2 + 1);
|
||||
info1 = btf_array(t1);
|
||||
info2 = btf_array(t2);
|
||||
return info1->type == info2->type &&
|
||||
info1->index_type == info2->index_type &&
|
||||
info1->nelems == info2->nelems;
|
||||
@@ -1927,14 +1902,10 @@ static bool btf_equal_array(struct btf_type *t1, struct btf_type *t2)
|
||||
*/
|
||||
static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_array *info1, *info2;
|
||||
|
||||
if (!btf_equal_common(t1, t2))
|
||||
return false;
|
||||
|
||||
info1 = (struct btf_array *)(t1 + 1);
|
||||
info2 = (struct btf_array *)(t2 + 1);
|
||||
return info1->nelems == info2->nelems;
|
||||
return btf_array(t1)->nelems == btf_array(t2)->nelems;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1944,8 +1915,8 @@ static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
|
||||
*/
|
||||
static long btf_hash_fnproto(struct btf_type *t)
|
||||
{
|
||||
struct btf_param *member = (struct btf_param *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
const struct btf_param *member = btf_params(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
long h = btf_hash_common(t);
|
||||
int i;
|
||||
|
||||
@@ -1966,16 +1937,16 @@ static long btf_hash_fnproto(struct btf_type *t)
|
||||
*/
|
||||
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_param *m1, *m2;
|
||||
const struct btf_param *m1, *m2;
|
||||
__u16 vlen;
|
||||
int i;
|
||||
|
||||
if (!btf_equal_common(t1, t2))
|
||||
return false;
|
||||
|
||||
vlen = BTF_INFO_VLEN(t1->info);
|
||||
m1 = (struct btf_param *)(t1 + 1);
|
||||
m2 = (struct btf_param *)(t2 + 1);
|
||||
vlen = btf_vlen(t1);
|
||||
m1 = btf_params(t1);
|
||||
m2 = btf_params(t2);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (m1->name_off != m2->name_off || m1->type != m2->type)
|
||||
return false;
|
||||
@@ -1992,7 +1963,7 @@ static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||
*/
|
||||
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||
{
|
||||
struct btf_param *m1, *m2;
|
||||
const struct btf_param *m1, *m2;
|
||||
__u16 vlen;
|
||||
int i;
|
||||
|
||||
@@ -2000,9 +1971,9 @@ static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
|
||||
if (t1->name_off != t2->name_off || t1->info != t2->info)
|
||||
return false;
|
||||
|
||||
vlen = BTF_INFO_VLEN(t1->info);
|
||||
m1 = (struct btf_param *)(t1 + 1);
|
||||
m2 = (struct btf_param *)(t2 + 1);
|
||||
vlen = btf_vlen(t1);
|
||||
m1 = btf_params(t1);
|
||||
m2 = btf_params(t2);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (m1->name_off != m2->name_off)
|
||||
return false;
|
||||
@@ -2028,7 +1999,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
|
||||
__u32 cand_id;
|
||||
long h;
|
||||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_RESTRICT:
|
||||
@@ -2141,13 +2112,13 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
|
||||
{
|
||||
__u32 orig_type_id = type_id;
|
||||
|
||||
if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
|
||||
if (!btf_is_fwd(d->btf->types[type_id]))
|
||||
return type_id;
|
||||
|
||||
while (is_type_mapped(d, type_id) && d->map[type_id] != type_id)
|
||||
type_id = d->map[type_id];
|
||||
|
||||
if (BTF_INFO_KIND(d->btf->types[type_id]->info) != BTF_KIND_FWD)
|
||||
if (!btf_is_fwd(d->btf->types[type_id]))
|
||||
return type_id;
|
||||
|
||||
return orig_type_id;
|
||||
@@ -2156,7 +2127,7 @@ static uint32_t resolve_fwd_id(struct btf_dedup *d, uint32_t type_id)
|
||||
|
||||
static inline __u16 btf_fwd_kind(struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KFLAG(t->info) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
|
||||
return btf_kflag(t) ? BTF_KIND_UNION : BTF_KIND_STRUCT;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2277,8 +2248,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
|
||||
cand_type = d->btf->types[cand_id];
|
||||
canon_type = d->btf->types[canon_id];
|
||||
cand_kind = BTF_INFO_KIND(cand_type->info);
|
||||
canon_kind = BTF_INFO_KIND(canon_type->info);
|
||||
cand_kind = btf_kind(cand_type);
|
||||
canon_kind = btf_kind(canon_type);
|
||||
|
||||
if (cand_type->name_off != canon_type->name_off)
|
||||
return 0;
|
||||
@@ -2327,12 +2298,12 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
struct btf_array *cand_arr, *canon_arr;
|
||||
const struct btf_array *cand_arr, *canon_arr;
|
||||
|
||||
if (!btf_compat_array(cand_type, canon_type))
|
||||
return 0;
|
||||
cand_arr = (struct btf_array *)(cand_type + 1);
|
||||
canon_arr = (struct btf_array *)(canon_type + 1);
|
||||
cand_arr = btf_array(cand_type);
|
||||
canon_arr = btf_array(canon_type);
|
||||
eq = btf_dedup_is_equiv(d,
|
||||
cand_arr->index_type, canon_arr->index_type);
|
||||
if (eq <= 0)
|
||||
@@ -2342,14 +2313,14 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
struct btf_member *cand_m, *canon_m;
|
||||
const struct btf_member *cand_m, *canon_m;
|
||||
__u16 vlen;
|
||||
|
||||
if (!btf_shallow_equal_struct(cand_type, canon_type))
|
||||
return 0;
|
||||
vlen = BTF_INFO_VLEN(cand_type->info);
|
||||
cand_m = (struct btf_member *)(cand_type + 1);
|
||||
canon_m = (struct btf_member *)(canon_type + 1);
|
||||
vlen = btf_vlen(cand_type);
|
||||
cand_m = btf_members(cand_type);
|
||||
canon_m = btf_members(canon_type);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
eq = btf_dedup_is_equiv(d, cand_m->type, canon_m->type);
|
||||
if (eq <= 0)
|
||||
@@ -2362,7 +2333,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
}
|
||||
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
struct btf_param *cand_p, *canon_p;
|
||||
const struct btf_param *cand_p, *canon_p;
|
||||
__u16 vlen;
|
||||
|
||||
if (!btf_compat_fnproto(cand_type, canon_type))
|
||||
@@ -2370,9 +2341,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
|
||||
eq = btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
|
||||
if (eq <= 0)
|
||||
return eq;
|
||||
vlen = BTF_INFO_VLEN(cand_type->info);
|
||||
cand_p = (struct btf_param *)(cand_type + 1);
|
||||
canon_p = (struct btf_param *)(canon_type + 1);
|
||||
vlen = btf_vlen(cand_type);
|
||||
cand_p = btf_params(cand_type);
|
||||
canon_p = btf_params(canon_type);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
eq = btf_dedup_is_equiv(d, cand_p->type, canon_p->type);
|
||||
if (eq <= 0)
|
||||
@@ -2427,8 +2398,8 @@ static void btf_dedup_merge_hypot_map(struct btf_dedup *d)
|
||||
targ_type_id = d->hypot_map[cand_type_id];
|
||||
t_id = resolve_type_id(d, targ_type_id);
|
||||
c_id = resolve_type_id(d, cand_type_id);
|
||||
t_kind = BTF_INFO_KIND(d->btf->types[t_id]->info);
|
||||
c_kind = BTF_INFO_KIND(d->btf->types[c_id]->info);
|
||||
t_kind = btf_kind(d->btf->types[t_id]);
|
||||
c_kind = btf_kind(d->btf->types[c_id]);
|
||||
/*
|
||||
* Resolve FWD into STRUCT/UNION.
|
||||
* It's ok to resolve FWD into STRUCT/UNION that's not yet
|
||||
@@ -2497,7 +2468,7 @@ static int btf_dedup_struct_type(struct btf_dedup *d, __u32 type_id)
|
||||
return 0;
|
||||
|
||||
t = d->btf->types[type_id];
|
||||
kind = BTF_INFO_KIND(t->info);
|
||||
kind = btf_kind(t);
|
||||
|
||||
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION)
|
||||
return 0;
|
||||
@@ -2592,7 +2563,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
||||
t = d->btf->types[type_id];
|
||||
d->map[type_id] = BTF_IN_PROGRESS_ID;
|
||||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_RESTRICT:
|
||||
@@ -2616,7 +2587,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
||||
break;
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
struct btf_array *info = (struct btf_array *)(t + 1);
|
||||
struct btf_array *info = btf_array(t);
|
||||
|
||||
ref_type_id = btf_dedup_ref_type(d, info->type);
|
||||
if (ref_type_id < 0)
|
||||
@@ -2650,8 +2621,8 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
|
||||
return ref_type_id;
|
||||
t->type = ref_type_id;
|
||||
|
||||
vlen = BTF_INFO_VLEN(t->info);
|
||||
param = (struct btf_param *)(t + 1);
|
||||
vlen = btf_vlen(t);
|
||||
param = btf_params(t);
|
||||
for (i = 0; i < vlen; i++) {
|
||||
ref_type_id = btf_dedup_ref_type(d, param->type);
|
||||
if (ref_type_id < 0)
|
||||
@@ -2791,7 +2762,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
||||
struct btf_type *t = d->btf->types[type_id];
|
||||
int i, r;
|
||||
|
||||
switch (BTF_INFO_KIND(t->info)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_ENUM:
|
||||
break;
|
||||
@@ -2811,7 +2782,7 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
||||
break;
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
struct btf_array *arr_info = (struct btf_array *)(t + 1);
|
||||
struct btf_array *arr_info = btf_array(t);
|
||||
|
||||
r = btf_dedup_remap_type_id(d, arr_info->type);
|
||||
if (r < 0)
|
||||
@@ -2826,8 +2797,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
||||
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
struct btf_member *member = (struct btf_member *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_member *member = btf_members(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
r = btf_dedup_remap_type_id(d, member->type);
|
||||
@@ -2840,8 +2811,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
||||
}
|
||||
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
struct btf_param *param = (struct btf_param *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_param *param = btf_params(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
r = btf_dedup_remap_type_id(d, t->type);
|
||||
if (r < 0)
|
||||
@@ -2859,8 +2830,8 @@ static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
|
||||
}
|
||||
|
||||
case BTF_KIND_DATASEC: {
|
||||
struct btf_var_secinfo *var = (struct btf_var_secinfo *)(t + 1);
|
||||
__u16 vlen = BTF_INFO_VLEN(t->info);
|
||||
struct btf_var_secinfo *var = btf_var_secinfos(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
r = btf_dedup_remap_type_id(d, var->type);
|
||||
|
||||
182
src/btf.h
182
src/btf.h
@@ -5,6 +5,7 @@
|
||||
#define __LIBBPF_BTF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -57,6 +58,10 @@ struct btf_ext_header {
|
||||
__u32 func_info_len;
|
||||
__u32 line_info_off;
|
||||
__u32 line_info_len;
|
||||
|
||||
/* optional part of .BTF.ext header */
|
||||
__u32 offset_reloc_off;
|
||||
__u32 offset_reloc_len;
|
||||
};
|
||||
|
||||
LIBBPF_API void btf__free(struct btf *btf);
|
||||
@@ -120,6 +125,183 @@ LIBBPF_API void btf_dump__free(struct btf_dump *d);
|
||||
|
||||
LIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);
|
||||
|
||||
/*
|
||||
* A set of helpers for easier BTF types handling
|
||||
*/
|
||||
static inline __u16 btf_kind(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info);
|
||||
}
|
||||
|
||||
static inline __u16 btf_vlen(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_VLEN(t->info);
|
||||
}
|
||||
|
||||
static inline bool btf_kflag(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KFLAG(t->info);
|
||||
}
|
||||
|
||||
static inline bool btf_is_int(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_INT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_ptr(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_PTR;
|
||||
}
|
||||
|
||||
static inline bool btf_is_array(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_ARRAY;
|
||||
}
|
||||
|
||||
static inline bool btf_is_struct(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_STRUCT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_union(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_UNION;
|
||||
}
|
||||
|
||||
static inline bool btf_is_composite(const struct btf_type *t)
|
||||
{
|
||||
__u16 kind = btf_kind(t);
|
||||
|
||||
return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
|
||||
}
|
||||
|
||||
static inline bool btf_is_enum(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_ENUM;
|
||||
}
|
||||
|
||||
static inline bool btf_is_fwd(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_FWD;
|
||||
}
|
||||
|
||||
static inline bool btf_is_typedef(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_TYPEDEF;
|
||||
}
|
||||
|
||||
static inline bool btf_is_volatile(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_VOLATILE;
|
||||
}
|
||||
|
||||
static inline bool btf_is_const(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_CONST;
|
||||
}
|
||||
|
||||
static inline bool btf_is_restrict(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_RESTRICT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_mod(const struct btf_type *t)
|
||||
{
|
||||
__u16 kind = btf_kind(t);
|
||||
|
||||
return kind == BTF_KIND_VOLATILE ||
|
||||
kind == BTF_KIND_CONST ||
|
||||
kind == BTF_KIND_RESTRICT;
|
||||
}
|
||||
|
||||
static inline bool btf_is_func(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_FUNC;
|
||||
}
|
||||
|
||||
static inline bool btf_is_func_proto(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_FUNC_PROTO;
|
||||
}
|
||||
|
||||
static inline bool btf_is_var(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_VAR;
|
||||
}
|
||||
|
||||
static inline bool btf_is_datasec(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_DATASEC;
|
||||
}
|
||||
|
||||
static inline __u8 btf_int_encoding(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INT_ENCODING(*(__u32 *)(t + 1));
|
||||
}
|
||||
|
||||
static inline __u8 btf_int_offset(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INT_OFFSET(*(__u32 *)(t + 1));
|
||||
}
|
||||
|
||||
static inline __u8 btf_int_bits(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INT_BITS(*(__u32 *)(t + 1));
|
||||
}
|
||||
|
||||
static inline struct btf_array *btf_array(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_array *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_enum *btf_enum(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_enum *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_member *btf_members(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_member *)(t + 1);
|
||||
}
|
||||
|
||||
/* Get bit offset of a member with specified index. */
|
||||
static inline __u32 btf_member_bit_offset(const struct btf_type *t,
|
||||
__u32 member_idx)
|
||||
{
|
||||
const struct btf_member *m = btf_members(t) + member_idx;
|
||||
bool kflag = btf_kflag(t);
|
||||
|
||||
return kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
|
||||
}
|
||||
/*
|
||||
* Get bitfield size of a member, assuming t is BTF_KIND_STRUCT or
|
||||
* BTF_KIND_UNION. If member is not a bitfield, zero is returned.
|
||||
*/
|
||||
static inline __u32 btf_member_bitfield_size(const struct btf_type *t,
|
||||
__u32 member_idx)
|
||||
{
|
||||
const struct btf_member *m = btf_members(t) + member_idx;
|
||||
bool kflag = btf_kflag(t);
|
||||
|
||||
return kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
||||
}
|
||||
|
||||
static inline struct btf_param *btf_params(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_param *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_var *btf_var(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_var *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_var_secinfo *
|
||||
btf_var_secinfos(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_var_secinfo *)(t + 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
232
src/btf_dump.c
232
src/btf_dump.c
@@ -48,6 +48,8 @@ struct btf_dump_type_aux_state {
|
||||
__u8 fwd_emitted: 1;
|
||||
/* whether unique non-duplicate name was already assigned */
|
||||
__u8 name_resolved: 1;
|
||||
/* whether type is referenced from any other type */
|
||||
__u8 referenced: 1;
|
||||
};
|
||||
|
||||
struct btf_dump {
|
||||
@@ -100,21 +102,6 @@ static bool str_equal_fn(const void *a, const void *b, void *ctx)
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static __u16 btf_kind_of(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info);
|
||||
}
|
||||
|
||||
static __u16 btf_vlen_of(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_VLEN(t->info);
|
||||
}
|
||||
|
||||
static bool btf_kflag_of(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KFLAG(t->info);
|
||||
}
|
||||
|
||||
static const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
|
||||
{
|
||||
return btf__name_by_offset(d->btf, name_off);
|
||||
@@ -188,6 +175,7 @@ void btf_dump__free(struct btf_dump *d)
|
||||
free(d);
|
||||
}
|
||||
|
||||
static int btf_dump_mark_referenced(struct btf_dump *d);
|
||||
static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);
|
||||
static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id);
|
||||
|
||||
@@ -228,6 +216,11 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
||||
/* VOID is special */
|
||||
d->type_states[0].order_state = ORDERED;
|
||||
d->type_states[0].emit_state = EMITTED;
|
||||
|
||||
/* eagerly determine referenced types for anon enums */
|
||||
err = btf_dump_mark_referenced(d);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
d->emit_queue_cnt = 0;
|
||||
@@ -241,6 +234,79 @@ int btf_dump__dump_type(struct btf_dump *d, __u32 id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark all types that are referenced from any other type. This is used to
|
||||
* determine top-level anonymous enums that need to be emitted as an
|
||||
* independent type declarations.
|
||||
* Anonymous enums come in two flavors: either embedded in a struct's field
|
||||
* definition, in which case they have to be declared inline as part of field
|
||||
* type declaration; or as a top-level anonymous enum, typically used for
|
||||
* declaring global constants. It's impossible to distinguish between two
|
||||
* without knowning whether given enum type was referenced from other type:
|
||||
* top-level anonymous enum won't be referenced by anything, while embedded
|
||||
* one will.
|
||||
*/
|
||||
static int btf_dump_mark_referenced(struct btf_dump *d)
|
||||
{
|
||||
int i, j, n = btf__get_nr_types(d->btf);
|
||||
const struct btf_type *t;
|
||||
__u16 vlen;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
t = btf__type_by_id(d->btf, i);
|
||||
vlen = btf_vlen(t);
|
||||
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_FWD:
|
||||
break;
|
||||
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_VAR:
|
||||
d->type_states[t->type].referenced = 1;
|
||||
break;
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = btf_array(t);
|
||||
|
||||
d->type_states[a->index_type].referenced = 1;
|
||||
d->type_states[a->type].referenced = 1;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
const struct btf_member *m = btf_members(t);
|
||||
|
||||
for (j = 0; j < vlen; j++, m++)
|
||||
d->type_states[m->type].referenced = 1;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
const struct btf_param *p = btf_params(t);
|
||||
|
||||
for (j = 0; j < vlen; j++, p++)
|
||||
d->type_states[p->type].referenced = 1;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_DATASEC: {
|
||||
const struct btf_var_secinfo *v = btf_var_secinfos(t);
|
||||
|
||||
for (j = 0; j < vlen; j++, v++)
|
||||
d->type_states[v->type].referenced = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
|
||||
{
|
||||
__u32 *new_queue;
|
||||
@@ -349,7 +415,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
*/
|
||||
struct btf_dump_type_aux_state *tstate = &d->type_states[id];
|
||||
const struct btf_type *t;
|
||||
__u16 kind, vlen;
|
||||
__u16 vlen;
|
||||
int err, i;
|
||||
|
||||
/* return true, letting typedefs know that it's ok to be emitted */
|
||||
@@ -357,18 +423,16 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
return 1;
|
||||
|
||||
t = btf__type_by_id(d->btf, id);
|
||||
kind = btf_kind_of(t);
|
||||
|
||||
if (tstate->order_state == ORDERING) {
|
||||
/* type loop, but resolvable through fwd declaration */
|
||||
if ((kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION) &&
|
||||
through_ptr && t->name_off != 0)
|
||||
if (btf_is_composite(t) && through_ptr && t->name_off != 0)
|
||||
return 0;
|
||||
pr_warning("unsatisfiable type cycle, id:[%u]\n", id);
|
||||
return -ELOOP;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_INT:
|
||||
tstate->order_state = ORDERED;
|
||||
return 0;
|
||||
@@ -378,14 +442,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
tstate->order_state = ORDERED;
|
||||
return err;
|
||||
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = (void *)(t + 1);
|
||||
case BTF_KIND_ARRAY:
|
||||
return btf_dump_order_type(d, btf_array(t)->type, through_ptr);
|
||||
|
||||
return btf_dump_order_type(d, a->type, through_ptr);
|
||||
}
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
const struct btf_member *m = (void *)(t + 1);
|
||||
const struct btf_member *m = btf_members(t);
|
||||
/*
|
||||
* struct/union is part of strong link, only if it's embedded
|
||||
* (so no ptr in a path) or it's anonymous (so has to be
|
||||
@@ -396,7 +458,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
|
||||
tstate->order_state = ORDERING;
|
||||
|
||||
vlen = btf_vlen_of(t);
|
||||
vlen = btf_vlen(t);
|
||||
for (i = 0; i < vlen; i++, m++) {
|
||||
err = btf_dump_order_type(d, m->type, false);
|
||||
if (err < 0)
|
||||
@@ -414,7 +476,12 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
}
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_FWD:
|
||||
if (t->name_off != 0) {
|
||||
/*
|
||||
* non-anonymous or non-referenced enums are top-level
|
||||
* declarations and should be emitted. Same logic can be
|
||||
* applied to FWDs, it won't hurt anyways.
|
||||
*/
|
||||
if (t->name_off != 0 || !tstate->referenced) {
|
||||
err = btf_dump_add_emit_queue_id(d, id);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -447,7 +514,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
return btf_dump_order_type(d, t->type, through_ptr);
|
||||
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
const struct btf_param *p = (void *)(t + 1);
|
||||
const struct btf_param *p = btf_params(t);
|
||||
bool is_strong;
|
||||
|
||||
err = btf_dump_order_type(d, t->type, through_ptr);
|
||||
@@ -455,7 +522,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
|
||||
return err;
|
||||
is_strong = err > 0;
|
||||
|
||||
vlen = btf_vlen_of(t);
|
||||
vlen = btf_vlen(t);
|
||||
for (i = 0; i < vlen; i++, p++) {
|
||||
err = btf_dump_order_type(d, p->type, through_ptr);
|
||||
if (err < 0)
|
||||
@@ -553,12 +620,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
return;
|
||||
|
||||
t = btf__type_by_id(d->btf, id);
|
||||
kind = btf_kind_of(t);
|
||||
|
||||
if (top_level_def && t->name_off == 0) {
|
||||
pr_warning("unexpected nameless definition, id:[%u]\n", id);
|
||||
return;
|
||||
}
|
||||
kind = btf_kind(t);
|
||||
|
||||
if (tstate->emit_state == EMITTING) {
|
||||
if (tstate->fwd_emitted)
|
||||
@@ -618,12 +680,9 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
case BTF_KIND_RESTRICT:
|
||||
btf_dump_emit_type(d, t->type, cont_id);
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = (void *)(t + 1);
|
||||
|
||||
btf_dump_emit_type(d, a->type, cont_id);
|
||||
case BTF_KIND_ARRAY:
|
||||
btf_dump_emit_type(d, btf_array(t)->type, cont_id);
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_FWD:
|
||||
btf_dump_emit_fwd_def(d, id, t);
|
||||
btf_dump_printf(d, ";\n\n");
|
||||
@@ -656,8 +715,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
* applicable
|
||||
*/
|
||||
if (top_level_def || t->name_off == 0) {
|
||||
const struct btf_member *m = (void *)(t + 1);
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
const struct btf_member *m = btf_members(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
int i, new_cont_id;
|
||||
|
||||
new_cont_id = t->name_off == 0 ? cont_id : id;
|
||||
@@ -678,8 +737,8 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
}
|
||||
break;
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
const struct btf_param *p = (void *)(t + 1);
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
const struct btf_param *p = btf_params(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
int i;
|
||||
|
||||
btf_dump_emit_type(d, t->type, cont_id);
|
||||
@@ -696,7 +755,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
|
||||
static int btf_align_of(const struct btf *btf, __u32 id)
|
||||
{
|
||||
const struct btf_type *t = btf__type_by_id(btf, id);
|
||||
__u16 kind = btf_kind_of(t);
|
||||
__u16 kind = btf_kind(t);
|
||||
|
||||
switch (kind) {
|
||||
case BTF_KIND_INT:
|
||||
@@ -709,15 +768,12 @@ static int btf_align_of(const struct btf *btf, __u32 id)
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
return btf_align_of(btf, t->type);
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = (void *)(t + 1);
|
||||
|
||||
return btf_align_of(btf, a->type);
|
||||
}
|
||||
case BTF_KIND_ARRAY:
|
||||
return btf_align_of(btf, btf_array(t)->type);
|
||||
case BTF_KIND_STRUCT:
|
||||
case BTF_KIND_UNION: {
|
||||
const struct btf_member *m = (void *)(t + 1);
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
const struct btf_member *m = btf_members(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
int i, align = 1;
|
||||
|
||||
for (i = 0; i < vlen; i++, m++)
|
||||
@@ -726,7 +782,7 @@ static int btf_align_of(const struct btf *btf, __u32 id)
|
||||
return align;
|
||||
}
|
||||
default:
|
||||
pr_warning("unsupported BTF_KIND:%u\n", btf_kind_of(t));
|
||||
pr_warning("unsupported BTF_KIND:%u\n", btf_kind(t));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -737,20 +793,18 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
|
||||
const struct btf_member *m;
|
||||
int align, i, bit_sz;
|
||||
__u16 vlen;
|
||||
bool kflag;
|
||||
|
||||
align = btf_align_of(btf, id);
|
||||
/* size of a non-packed struct has to be a multiple of its alignment*/
|
||||
if (t->size % align)
|
||||
return true;
|
||||
|
||||
m = (void *)(t + 1);
|
||||
kflag = btf_kflag_of(t);
|
||||
vlen = btf_vlen_of(t);
|
||||
m = btf_members(t);
|
||||
vlen = btf_vlen(t);
|
||||
/* all non-bitfield fields have to be naturally aligned */
|
||||
for (i = 0; i < vlen; i++, m++) {
|
||||
align = btf_align_of(btf, m->type);
|
||||
bit_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
||||
bit_sz = btf_member_bitfield_size(t, i);
|
||||
if (bit_sz == 0 && m->offset % (8 * align) != 0)
|
||||
return true;
|
||||
}
|
||||
@@ -807,7 +861,7 @@ static void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,
|
||||
const struct btf_type *t)
|
||||
{
|
||||
btf_dump_printf(d, "%s %s",
|
||||
btf_kind_of(t) == BTF_KIND_STRUCT ? "struct" : "union",
|
||||
btf_is_struct(t) ? "struct" : "union",
|
||||
btf_dump_type_name(d, id));
|
||||
}
|
||||
|
||||
@@ -816,12 +870,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
||||
const struct btf_type *t,
|
||||
int lvl)
|
||||
{
|
||||
const struct btf_member *m = (void *)(t + 1);
|
||||
bool kflag = btf_kflag_of(t), is_struct;
|
||||
const struct btf_member *m = btf_members(t);
|
||||
bool is_struct = btf_is_struct(t);
|
||||
int align, i, packed, off = 0;
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
|
||||
is_struct = btf_kind_of(t) == BTF_KIND_STRUCT;
|
||||
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
|
||||
align = packed ? 1 : btf_align_of(d->btf, id);
|
||||
|
||||
@@ -835,8 +888,8 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
|
||||
int m_off, m_sz;
|
||||
|
||||
fname = btf_name_of(d, m->name_off);
|
||||
m_sz = kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;
|
||||
m_off = kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;
|
||||
m_sz = btf_member_bitfield_size(t, i);
|
||||
m_off = btf_member_bit_offset(t, i);
|
||||
align = packed ? 1 : btf_align_of(d->btf, m->type);
|
||||
|
||||
btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
|
||||
@@ -870,8 +923,8 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
||||
const struct btf_type *t,
|
||||
int lvl)
|
||||
{
|
||||
const struct btf_enum *v = (void *)(t+1);
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
const struct btf_enum *v = btf_enum(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
const char *name;
|
||||
size_t dup_cnt;
|
||||
int i;
|
||||
@@ -905,7 +958,7 @@ static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
||||
{
|
||||
const char *name = btf_dump_type_name(d, id);
|
||||
|
||||
if (btf_kflag_of(t))
|
||||
if (btf_kflag(t))
|
||||
btf_dump_printf(d, "union %s", name);
|
||||
else
|
||||
btf_dump_printf(d, "struct %s", name);
|
||||
@@ -987,7 +1040,6 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
struct id_stack decl_stack;
|
||||
const struct btf_type *t;
|
||||
int err, stack_start;
|
||||
__u16 kind;
|
||||
|
||||
stack_start = d->decl_stack_cnt;
|
||||
for (;;) {
|
||||
@@ -1008,8 +1060,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
break;
|
||||
|
||||
t = btf__type_by_id(d->btf, id);
|
||||
kind = btf_kind_of(t);
|
||||
switch (kind) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
@@ -1017,12 +1068,9 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
id = t->type;
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = (void *)(t + 1);
|
||||
|
||||
id = a->type;
|
||||
case BTF_KIND_ARRAY:
|
||||
id = btf_array(t)->type;
|
||||
break;
|
||||
}
|
||||
case BTF_KIND_INT:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_FWD:
|
||||
@@ -1032,7 +1080,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
|
||||
goto done;
|
||||
default:
|
||||
pr_warning("unexpected type in decl chain, kind:%u, id:[%u]\n",
|
||||
kind, id);
|
||||
btf_kind(t), id);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@@ -1070,7 +1118,7 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
|
||||
id = decl_stack->ids[decl_stack->cnt - 1];
|
||||
t = btf__type_by_id(d->btf, id);
|
||||
|
||||
switch (btf_kind_of(t)) {
|
||||
switch (btf_kind(t)) {
|
||||
case BTF_KIND_VOLATILE:
|
||||
btf_dump_printf(d, "volatile ");
|
||||
break;
|
||||
@@ -1087,20 +1135,6 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
|
||||
}
|
||||
}
|
||||
|
||||
static bool btf_is_mod_kind(const struct btf *btf, __u32 id)
|
||||
{
|
||||
const struct btf_type *t = btf__type_by_id(btf, id);
|
||||
|
||||
switch (btf_kind_of(t)) {
|
||||
case BTF_KIND_VOLATILE:
|
||||
case BTF_KIND_CONST:
|
||||
case BTF_KIND_RESTRICT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void btf_dump_emit_name(const struct btf_dump *d,
|
||||
const char *name, bool last_was_ptr)
|
||||
{
|
||||
@@ -1139,7 +1173,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
}
|
||||
|
||||
t = btf__type_by_id(d->btf, id);
|
||||
kind = btf_kind_of(t);
|
||||
kind = btf_kind(t);
|
||||
|
||||
switch (kind) {
|
||||
case BTF_KIND_INT:
|
||||
@@ -1185,7 +1219,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
btf_dump_printf(d, " restrict");
|
||||
break;
|
||||
case BTF_KIND_ARRAY: {
|
||||
const struct btf_array *a = (void *)(t + 1);
|
||||
const struct btf_array *a = btf_array(t);
|
||||
const struct btf_type *next_t;
|
||||
__u32 next_id;
|
||||
bool multidim;
|
||||
@@ -1201,7 +1235,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
*/
|
||||
while (decls->cnt) {
|
||||
next_id = decls->ids[decls->cnt - 1];
|
||||
if (btf_is_mod_kind(d->btf, next_id))
|
||||
next_t = btf__type_by_id(d->btf, next_id);
|
||||
if (btf_is_mod(next_t))
|
||||
decls->cnt--;
|
||||
else
|
||||
break;
|
||||
@@ -1213,8 +1248,9 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
return;
|
||||
}
|
||||
|
||||
next_id = decls->ids[decls->cnt - 1];
|
||||
next_t = btf__type_by_id(d->btf, next_id);
|
||||
multidim = btf_kind_of(next_t) == BTF_KIND_ARRAY;
|
||||
multidim = btf_is_array(next_t);
|
||||
/* we need space if we have named non-pointer */
|
||||
if (fname[0] && !last_was_ptr)
|
||||
btf_dump_printf(d, " ");
|
||||
@@ -1228,8 +1264,8 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
|
||||
return;
|
||||
}
|
||||
case BTF_KIND_FUNC_PROTO: {
|
||||
const struct btf_param *p = (void *)(t + 1);
|
||||
__u16 vlen = btf_vlen_of(t);
|
||||
const struct btf_param *p = btf_params(t);
|
||||
__u16 vlen = btf_vlen(t);
|
||||
int i;
|
||||
|
||||
btf_dump_emit_mods(d, decls);
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <bits/wordsize.h>
|
||||
#else
|
||||
#include <bits/reg.h>
|
||||
#endif
|
||||
#include "libbpf_internal.h"
|
||||
|
||||
static inline size_t hash_bits(size_t h, int bits)
|
||||
|
||||
1059
src/libbpf.c
1059
src/libbpf.c
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@ enum libbpf_print_level {
|
||||
typedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,
|
||||
const char *, va_list ap);
|
||||
|
||||
LIBBPF_API void libbpf_set_print(libbpf_print_fn_t fn);
|
||||
LIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);
|
||||
|
||||
/* Hide internal to user */
|
||||
struct bpf_object;
|
||||
@@ -92,6 +92,7 @@ LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
||||
struct bpf_object_load_attr {
|
||||
struct bpf_object *obj;
|
||||
int log_level;
|
||||
const char *target_btf_path;
|
||||
};
|
||||
|
||||
/* Load/unload object into/from kernel */
|
||||
|
||||
@@ -183,4 +183,10 @@ LIBBPF_0.0.4 {
|
||||
perf_buffer__new;
|
||||
perf_buffer__new_raw;
|
||||
perf_buffer__poll;
|
||||
xsk_umem__create;
|
||||
} LIBBPF_0.0.3;
|
||||
|
||||
LIBBPF_0.0.5 {
|
||||
global:
|
||||
bpf_btf_get_next_id;
|
||||
} LIBBPF_0.0.4;
|
||||
|
||||
@@ -29,6 +29,26 @@
|
||||
#ifndef max
|
||||
# define max(x, y) ((x) < (y) ? (y) : (x))
|
||||
#endif
|
||||
#ifndef offsetofend
|
||||
# define offsetofend(TYPE, FIELD) \
|
||||
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
|
||||
#endif
|
||||
|
||||
/* Symbol versioning is different between static and shared library.
|
||||
* Properly versioned symbols are needed for shared library, but
|
||||
* only the symbol of the new version is needed for static library.
|
||||
*/
|
||||
#ifdef SHARED
|
||||
# define COMPAT_VERSION(internal_name, api_name, version) \
|
||||
asm(".symver " #internal_name "," #api_name "@" #version);
|
||||
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
asm(".symver " #internal_name "," #api_name "@@" #version);
|
||||
#else
|
||||
# define COMPAT_VERSION(internal_name, api_name, version)
|
||||
# define DEFAULT_VERSION(internal_name, api_name, version) \
|
||||
extern typeof(internal_name) api_name \
|
||||
__attribute__((alias(#internal_name)));
|
||||
#endif
|
||||
|
||||
extern void libbpf_print(enum libbpf_print_level level,
|
||||
const char *format, ...)
|
||||
@@ -46,4 +66,105 @@ do { \
|
||||
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
|
||||
const char *str_sec, size_t str_len);
|
||||
|
||||
struct btf_ext_info {
|
||||
/*
|
||||
* info points to the individual info section (e.g. func_info and
|
||||
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
|
||||
*/
|
||||
void *info;
|
||||
__u32 rec_size;
|
||||
__u32 len;
|
||||
};
|
||||
|
||||
#define for_each_btf_ext_sec(seg, sec) \
|
||||
for (sec = (seg)->info; \
|
||||
(void *)sec < (seg)->info + (seg)->len; \
|
||||
sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
|
||||
(seg)->rec_size * sec->num_info)
|
||||
|
||||
#define for_each_btf_ext_rec(seg, sec, i, rec) \
|
||||
for (i = 0, rec = (void *)&(sec)->data; \
|
||||
i < (sec)->num_info; \
|
||||
i++, rec = (void *)rec + (seg)->rec_size)
|
||||
|
||||
struct btf_ext {
|
||||
union {
|
||||
struct btf_ext_header *hdr;
|
||||
void *data;
|
||||
};
|
||||
struct btf_ext_info func_info;
|
||||
struct btf_ext_info line_info;
|
||||
struct btf_ext_info offset_reloc_info;
|
||||
__u32 data_size;
|
||||
};
|
||||
|
||||
struct btf_ext_info_sec {
|
||||
__u32 sec_name_off;
|
||||
__u32 num_info;
|
||||
/* Followed by num_info * record_size number of bytes */
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
/* The minimum bpf_func_info checked by the loader */
|
||||
struct bpf_func_info_min {
|
||||
__u32 insn_off;
|
||||
__u32 type_id;
|
||||
};
|
||||
|
||||
/* The minimum bpf_line_info checked by the loader */
|
||||
struct bpf_line_info_min {
|
||||
__u32 insn_off;
|
||||
__u32 file_name_off;
|
||||
__u32 line_off;
|
||||
__u32 line_col;
|
||||
};
|
||||
|
||||
/* The minimum bpf_offset_reloc checked by the loader
|
||||
*
|
||||
* Offset relocation captures the following data:
|
||||
* - insn_off - instruction offset (in bytes) within a BPF program that needs
|
||||
* its insn->imm field to be relocated with actual offset;
|
||||
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
|
||||
* offset;
|
||||
* - access_str_off - offset into corresponding .BTF string section. String
|
||||
* itself encodes an accessed field using a sequence of field and array
|
||||
* indicies, separated by colon (:). It's conceptually very close to LLVM's
|
||||
* getelementptr ([0]) instruction's arguments for identifying offset to
|
||||
* a field.
|
||||
*
|
||||
* Example to provide a better feel.
|
||||
*
|
||||
* struct sample {
|
||||
* int a;
|
||||
* struct {
|
||||
* int b[10];
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* struct sample *s = ...;
|
||||
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||
* // b is field #0 inside anon struct, accessing elem #5)
|
||||
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||
*
|
||||
* type_id for all relocs in this example will capture BTF type id of
|
||||
* `struct sample`.
|
||||
*
|
||||
* Such relocation is emitted when using __builtin_preserve_access_index()
|
||||
* Clang built-in, passing expression that captures field address, e.g.:
|
||||
*
|
||||
* bpf_probe_read(&dst, sizeof(dst),
|
||||
* __builtin_preserve_access_index(&src->a.b.c));
|
||||
*
|
||||
* In this case Clang will emit offset relocation recording necessary data to
|
||||
* be able to find offset of embedded `a.b.c` field within `src` struct.
|
||||
*
|
||||
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
||||
*/
|
||||
struct bpf_offset_reloc {
|
||||
__u32 insn_off;
|
||||
__u32 type_id;
|
||||
__u32 access_str_off;
|
||||
};
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
|
||||
|
||||
@@ -244,6 +244,7 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
|
||||
case BPF_MAP_TYPE_ARRAY_OF_MAPS:
|
||||
case BPF_MAP_TYPE_HASH_OF_MAPS:
|
||||
case BPF_MAP_TYPE_DEVMAP:
|
||||
case BPF_MAP_TYPE_DEVMAP_HASH:
|
||||
case BPF_MAP_TYPE_SOCKMAP:
|
||||
case BPF_MAP_TYPE_CPUMAP:
|
||||
case BPF_MAP_TYPE_XSKMAP:
|
||||
|
||||
108
src/xsk.c
108
src/xsk.c
@@ -65,7 +65,6 @@ struct xsk_socket {
|
||||
int xsks_map_fd;
|
||||
__u32 queue_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
bool zc;
|
||||
};
|
||||
|
||||
struct xsk_nl_info {
|
||||
@@ -74,23 +73,6 @@ struct xsk_nl_info {
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* For 32-bit systems, we need to use mmap2 as the offsets are 64-bit.
|
||||
* Unfortunately, it is not part of glibc.
|
||||
*/
|
||||
static inline void *xsk_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, __u64 offset)
|
||||
{
|
||||
#ifdef __NR_mmap2
|
||||
unsigned int page_shift = __builtin_ffs(getpagesize()) - 1;
|
||||
long ret = syscall(__NR_mmap2, addr, length, prot, flags, fd,
|
||||
(off_t)(offset >> page_shift));
|
||||
|
||||
return (void *)ret;
|
||||
#else
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
int xsk_umem__fd(const struct xsk_umem *umem)
|
||||
{
|
||||
return umem ? umem->fd : -EINVAL;
|
||||
@@ -116,6 +98,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
||||
cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
|
||||
cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
|
||||
cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
|
||||
cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,6 +106,7 @@ static void xsk_set_umem_config(struct xsk_umem_config *cfg,
|
||||
cfg->comp_size = usr_cfg->comp_size;
|
||||
cfg->frame_size = usr_cfg->frame_size;
|
||||
cfg->frame_headroom = usr_cfg->frame_headroom;
|
||||
cfg->flags = usr_cfg->flags;
|
||||
}
|
||||
|
||||
static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
||||
@@ -149,9 +133,10 @@ static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill, struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *usr_config)
|
||||
int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
__u64 size, struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *usr_config)
|
||||
{
|
||||
struct xdp_mmap_offsets off;
|
||||
struct xdp_umem_reg mr;
|
||||
@@ -182,6 +167,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
||||
mr.len = size;
|
||||
mr.chunk_size = umem->config.frame_size;
|
||||
mr.headroom = umem->config.frame_headroom;
|
||||
mr.flags = umem->config.flags;
|
||||
|
||||
err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
|
||||
if (err) {
|
||||
@@ -210,10 +196,9 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
||||
goto out_socket;
|
||||
}
|
||||
|
||||
map = xsk_mmap(NULL, off.fr.desc +
|
||||
umem->config.fill_size * sizeof(__u64),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||
umem->fd, XDP_UMEM_PGOFF_FILL_RING);
|
||||
map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||
XDP_UMEM_PGOFF_FILL_RING);
|
||||
if (map == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_socket;
|
||||
@@ -224,13 +209,13 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
||||
fill->size = umem->config.fill_size;
|
||||
fill->producer = map + off.fr.producer;
|
||||
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;
|
||||
|
||||
map = xsk_mmap(NULL,
|
||||
off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||
umem->fd, XDP_UMEM_PGOFF_COMPLETION_RING);
|
||||
map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, umem->fd,
|
||||
XDP_UMEM_PGOFF_COMPLETION_RING);
|
||||
if (map == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_mmap;
|
||||
@@ -241,6 +226,7 @@ int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
|
||||
comp->size = umem->config.comp_size;
|
||||
comp->producer = map + off.cr.producer;
|
||||
comp->consumer = map + off.cr.consumer;
|
||||
comp->flags = map + off.cr.flags;
|
||||
comp->ring = map + off.cr.desc;
|
||||
|
||||
*umem_ptr = umem;
|
||||
@@ -255,6 +241,29 @@ out_umem_alloc:
|
||||
return err;
|
||||
}
|
||||
|
||||
struct xsk_umem_config_v1 {
|
||||
__u32 fill_size;
|
||||
__u32 comp_size;
|
||||
__u32 frame_size;
|
||||
__u32 frame_headroom;
|
||||
};
|
||||
|
||||
int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
|
||||
__u64 size, struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *usr_config)
|
||||
{
|
||||
struct xsk_umem_config config;
|
||||
|
||||
memcpy(&config, usr_config, sizeof(struct xsk_umem_config_v1));
|
||||
config.flags = 0;
|
||||
|
||||
return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp,
|
||||
&config);
|
||||
}
|
||||
COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
|
||||
DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
|
||||
|
||||
static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||
{
|
||||
static const int log_buf_size = 16 * 1024;
|
||||
@@ -317,17 +326,16 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
|
||||
|
||||
static int xsk_get_max_queues(struct xsk_socket *xsk)
|
||||
{
|
||||
struct ethtool_channels channels;
|
||||
struct ifreq ifr;
|
||||
struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
|
||||
struct ifreq ifr = {};
|
||||
int fd, err, ret;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
channels.cmd = ETHTOOL_GCHANNELS;
|
||||
ifr.ifr_data = (void *)&channels;
|
||||
strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
|
||||
memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||
err = ioctl(fd, SIOCETHTOOL, &ifr);
|
||||
if (err && errno != EOPNOTSUPP) {
|
||||
@@ -335,7 +343,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (channels.max_combined == 0 || errno == EOPNOTSUPP)
|
||||
if (err || channels.max_combined == 0)
|
||||
/* If the device says it has no channels, then all traffic
|
||||
* is sent to a single stream, so max queues = 1.
|
||||
*/
|
||||
@@ -482,7 +490,6 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
void *rx_map = NULL, *tx_map = NULL;
|
||||
struct sockaddr_xdp sxdp = {};
|
||||
struct xdp_mmap_offsets off;
|
||||
struct xdp_options opts;
|
||||
struct xsk_socket *xsk;
|
||||
socklen_t optlen;
|
||||
int err;
|
||||
@@ -517,7 +524,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
err = -errno;
|
||||
goto out_socket;
|
||||
}
|
||||
strncpy(xsk->ifname, ifname, IFNAMSIZ - 1);
|
||||
memcpy(xsk->ifname, ifname, IFNAMSIZ - 1);
|
||||
xsk->ifname[IFNAMSIZ - 1] = '\0';
|
||||
|
||||
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
|
||||
@@ -551,11 +558,10 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
}
|
||||
|
||||
if (rx) {
|
||||
rx_map = xsk_mmap(NULL, off.rx.desc +
|
||||
xsk->config.rx_size * sizeof(struct xdp_desc),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_POPULATE,
|
||||
xsk->fd, XDP_PGOFF_RX_RING);
|
||||
rx_map = mmap(NULL, off.rx.desc +
|
||||
xsk->config.rx_size * sizeof(struct xdp_desc),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||
xsk->fd, XDP_PGOFF_RX_RING);
|
||||
if (rx_map == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_socket;
|
||||
@@ -565,16 +571,16 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
rx->size = xsk->config.rx_size;
|
||||
rx->producer = rx_map + off.rx.producer;
|
||||
rx->consumer = rx_map + off.rx.consumer;
|
||||
rx->flags = rx_map + off.rx.flags;
|
||||
rx->ring = rx_map + off.rx.desc;
|
||||
}
|
||||
xsk->rx = rx;
|
||||
|
||||
if (tx) {
|
||||
tx_map = xsk_mmap(NULL, off.tx.desc +
|
||||
xsk->config.tx_size * sizeof(struct xdp_desc),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_POPULATE,
|
||||
xsk->fd, XDP_PGOFF_TX_RING);
|
||||
tx_map = mmap(NULL, off.tx.desc +
|
||||
xsk->config.tx_size * sizeof(struct xdp_desc),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
|
||||
xsk->fd, XDP_PGOFF_TX_RING);
|
||||
if (tx_map == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_mmap_rx;
|
||||
@@ -584,6 +590,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
tx->size = xsk->config.tx_size;
|
||||
tx->producer = tx_map + off.tx.producer;
|
||||
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;
|
||||
}
|
||||
@@ -602,15 +609,6 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
|
||||
|
||||
xsk->prog_fd = -1;
|
||||
|
||||
optlen = sizeof(opts);
|
||||
err = getsockopt(xsk->fd, SOL_XDP, XDP_OPTIONS, &opts, &optlen);
|
||||
if (err) {
|
||||
err = -errno;
|
||||
goto out_mmap_tx;
|
||||
}
|
||||
|
||||
xsk->zc = opts.flags & XDP_OPTIONS_ZEROCOPY;
|
||||
|
||||
if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
|
||||
err = xsk_setup_xdp_prog(xsk);
|
||||
if (err)
|
||||
|
||||
33
src/xsk.h
33
src/xsk.h
@@ -32,6 +32,7 @@ struct name { \
|
||||
__u32 *producer; \
|
||||
__u32 *consumer; \
|
||||
void *ring; \
|
||||
__u32 *flags; \
|
||||
}
|
||||
|
||||
DEFINE_XSK_RING(xsk_ring_prod);
|
||||
@@ -76,6 +77,11 @@ xsk_ring_cons__rx_desc(const struct xsk_ring_cons *rx, __u32 idx)
|
||||
return &descs[idx & rx->mask];
|
||||
}
|
||||
|
||||
static inline int xsk_ring_prod__needs_wakeup(const struct xsk_ring_prod *r)
|
||||
{
|
||||
return *r->flags & XDP_RING_NEED_WAKEUP;
|
||||
}
|
||||
|
||||
static inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)
|
||||
{
|
||||
__u32 free_entries = r->cached_cons - r->cached_prod;
|
||||
@@ -162,6 +168,21 @@ static inline void *xsk_umem__get_data(void *umem_area, __u64 addr)
|
||||
return &((char *)umem_area)[addr];
|
||||
}
|
||||
|
||||
static inline __u64 xsk_umem__extract_addr(__u64 addr)
|
||||
{
|
||||
return addr & XSK_UNALIGNED_BUF_ADDR_MASK;
|
||||
}
|
||||
|
||||
static inline __u64 xsk_umem__extract_offset(__u64 addr)
|
||||
{
|
||||
return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;
|
||||
}
|
||||
|
||||
static inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)
|
||||
{
|
||||
return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);
|
||||
}
|
||||
|
||||
LIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);
|
||||
LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
|
||||
@@ -170,12 +191,14 @@ LIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);
|
||||
#define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */
|
||||
#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)
|
||||
#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0
|
||||
#define XSK_UMEM__DEFAULT_FLAGS 0
|
||||
|
||||
struct xsk_umem_config {
|
||||
__u32 fill_size;
|
||||
__u32 comp_size;
|
||||
__u32 frame_size;
|
||||
__u32 frame_headroom;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
/* Flags for the libbpf_flags field. */
|
||||
@@ -195,6 +218,16 @@ LIBBPF_API int xsk_umem__create(struct xsk_umem **umem,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,
|
||||
void *umem_area, __u64 size,
|
||||
struct xsk_ring_prod *fill,
|
||||
struct xsk_ring_cons *comp,
|
||||
const struct xsk_umem_config *config);
|
||||
LIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,
|
||||
const char *ifname, __u32 queue_id,
|
||||
struct xsk_umem *umem,
|
||||
|
||||
@@ -13,6 +13,10 @@ function info() {
|
||||
echo -e "\033[33;1m$1\033[0m"
|
||||
}
|
||||
|
||||
function error() {
|
||||
echo -e "\033[31;1m$1\033[0m"
|
||||
}
|
||||
|
||||
function docker_exec() {
|
||||
docker exec $ENV_VARS -it $CONT_NAME "$@"
|
||||
}
|
||||
@@ -26,43 +30,41 @@ for phase in "${PHASES[@]}"; do
|
||||
SETUP)
|
||||
info "Setup phase"
|
||||
info "Using Debian $DEBIAN_RELEASE"
|
||||
docker pull debian:$DEBIAN_RELEASE
|
||||
docker pull debian:$DEBIAN_RELEASE
|
||||
info "Starting container $CONT_NAME"
|
||||
$DOCKER_RUN -v $REPO_ROOT:/build:rw \
|
||||
-w /build --privileged=true --name $CONT_NAME \
|
||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||
-dit --net=host debian:$DEBIAN_RELEASE /bin/bash
|
||||
docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
|
||||
docker_exec apt-get -y update
|
||||
docker_exec apt-get -y build-dep libelf-dev
|
||||
docker_exec apt-get -y install libelf-dev
|
||||
docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
|
||||
;;
|
||||
RUN|RUN_CLANG|RUN_GCC8)
|
||||
if [[ "$phase" = "RUN_CLANG" ]]; then
|
||||
RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
||||
if [[ "$phase" = *"CLANG"* ]]; then
|
||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||
CC="clang"
|
||||
elif [[ "$phase" = "RUN_GCC8" ]]; then
|
||||
elif [[ "$phase" = *"GCC8"* ]]; then
|
||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
||||
CC="gcc-8"
|
||||
fi
|
||||
docker_exec mkdir build
|
||||
docker_exec ${CC:-cc} --version
|
||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
docker_exec rm -rf build
|
||||
;;
|
||||
RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
|
||||
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
|
||||
ENV_VARS="-e CC=clang -e CXX=clang++"
|
||||
CC="clang"
|
||||
elif [[ "$phase" = "RUN_GCC8_ASAN" ]]; then
|
||||
ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
|
||||
CC="gcc-8"
|
||||
if [[ "$phase" = *"ASAN"* ]]; then
|
||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||
fi
|
||||
CFLAGS="${CFLAGS} -fsanitize=address,undefined"
|
||||
docker_exec mkdir build
|
||||
docker_exec mkdir build install
|
||||
docker_exec ${CC:-cc} --version
|
||||
info "build"
|
||||
docker_exec make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
docker_exec rm -rf build
|
||||
info "ldd build/libbpf.so:"
|
||||
docker_exec ldd build/libbpf.so
|
||||
if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
|
||||
error "No reference to libelf.so in libbpf.so!"
|
||||
exit 1
|
||||
fi
|
||||
info "install"
|
||||
docker_exec make -C src OBJDIR=../build DESTDIR=../install install
|
||||
docker_exec rm -rf build install
|
||||
;;
|
||||
CLEANUP)
|
||||
info "Cleanup phase"
|
||||
|
||||
@@ -11,7 +11,13 @@ source "$(dirname $0)/travis_wait.bash"
|
||||
cd $REPO_ROOT
|
||||
|
||||
CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
|
||||
mkdir build
|
||||
mkdir build install
|
||||
cc --version
|
||||
make CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
|
||||
rm -rf 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
|
||||
rm -rf build install
|
||||
|
||||
Reference in New Issue
Block a user