Commit 17ccf9e3 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Daniel Borkmann says:

====================
pull-request: bpf-next 2019-07-09

The following pull-request contains BPF updates for your *net-next* tree.

The main changes are:

1) Lots of libbpf improvements: i) addition of new APIs to attach BPF
   programs to tracing entities such as {k,u}probes or tracepoints,
   ii) improve specification of BTF-defined maps by eliminating the
   need for data initialization for some of the members, iii) addition
   of a high-level API for setting up and polling perf buffers for
   BPF event output helpers, all from Andrii.

2) Add "prog run" subcommand to bpftool in order to test-run programs
   through the kernel testing infrastructure of BPF, from Quentin.

3) Improve verifier for BPF sockaddr programs to support 8-byte stores
   for user_ip6 and msg_src_ip6 members given clang tends to generate
   such stores, from Stanislav.

4) Enable the new BPF JIT zero-extension optimization for further
   riscv64 ALU ops, from Luke.

5) Fix a bpftool json JIT dump crash on powerpc, from Jiri.

6) Fix an AF_XDP race in generic XDP's receive path, from Ilya.

7) Various smaller fixes from Ilya, Yue and Arnd.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7650b1a9 bf0bdd13
...@@ -757,31 +757,31 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, ...@@ -757,31 +757,31 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
case BPF_ALU | BPF_ADD | BPF_X: case BPF_ALU | BPF_ADD | BPF_X:
case BPF_ALU64 | BPF_ADD | BPF_X: case BPF_ALU64 | BPF_ADD | BPF_X:
emit(is64 ? rv_add(rd, rd, rs) : rv_addw(rd, rd, rs), ctx); emit(is64 ? rv_add(rd, rd, rs) : rv_addw(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_SUB | BPF_X: case BPF_ALU | BPF_SUB | BPF_X:
case BPF_ALU64 | BPF_SUB | BPF_X: case BPF_ALU64 | BPF_SUB | BPF_X:
emit(is64 ? rv_sub(rd, rd, rs) : rv_subw(rd, rd, rs), ctx); emit(is64 ? rv_sub(rd, rd, rs) : rv_subw(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_AND | BPF_X: case BPF_ALU | BPF_AND | BPF_X:
case BPF_ALU64 | BPF_AND | BPF_X: case BPF_ALU64 | BPF_AND | BPF_X:
emit(rv_and(rd, rd, rs), ctx); emit(rv_and(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_OR | BPF_X: case BPF_ALU | BPF_OR | BPF_X:
case BPF_ALU64 | BPF_OR | BPF_X: case BPF_ALU64 | BPF_OR | BPF_X:
emit(rv_or(rd, rd, rs), ctx); emit(rv_or(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_XOR | BPF_X: case BPF_ALU | BPF_XOR | BPF_X:
case BPF_ALU64 | BPF_XOR | BPF_X: case BPF_ALU64 | BPF_XOR | BPF_X:
emit(rv_xor(rd, rd, rs), ctx); emit(rv_xor(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_MUL | BPF_X: case BPF_ALU | BPF_MUL | BPF_X:
...@@ -811,13 +811,13 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, ...@@ -811,13 +811,13 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
case BPF_ALU | BPF_RSH | BPF_X: case BPF_ALU | BPF_RSH | BPF_X:
case BPF_ALU64 | BPF_RSH | BPF_X: case BPF_ALU64 | BPF_RSH | BPF_X:
emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx); emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
case BPF_ALU | BPF_ARSH | BPF_X: case BPF_ALU | BPF_ARSH | BPF_X:
case BPF_ALU64 | BPF_ARSH | BPF_X: case BPF_ALU64 | BPF_ARSH | BPF_X:
emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx); emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
...@@ -826,7 +826,7 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, ...@@ -826,7 +826,7 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
case BPF_ALU64 | BPF_NEG: case BPF_ALU64 | BPF_NEG:
emit(is64 ? rv_sub(rd, RV_REG_ZERO, rd) : emit(is64 ? rv_sub(rd, RV_REG_ZERO, rd) :
rv_subw(rd, RV_REG_ZERO, rd), ctx); rv_subw(rd, RV_REG_ZERO, rd), ctx);
if (!is64) if (!is64 && !aux->verifier_zext)
emit_zext_32(rd, ctx); emit_zext_32(rd, ctx);
break; break;
......
...@@ -747,6 +747,12 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default) ...@@ -747,6 +747,12 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default)
return size <= size_default && (size & (size - 1)) == 0; return size <= size_default && (size & (size - 1)) == 0;
} }
#define bpf_ctx_wide_store_ok(off, size, type, field) \
(size == sizeof(__u64) && \
off >= offsetof(type, field) && \
off + sizeof(__u64) <= offsetofend(type, field) && \
off % sizeof(__u64) == 0)
#define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0])) #define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0]))
static inline void bpf_prog_lock_ro(struct bpf_prog *fp) static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
......
...@@ -2223,9 +2223,7 @@ static inline bool tcp_bpf_ca_needs_ecn(struct sock *sk) ...@@ -2223,9 +2223,7 @@ static inline bool tcp_bpf_ca_needs_ecn(struct sock *sk)
static inline void tcp_bpf_rtt(struct sock *sk) static inline void tcp_bpf_rtt(struct sock *sk)
{ {
struct tcp_sock *tp = tcp_sk(sk); if (BPF_SOCK_OPS_TEST_FLAG(tcp_sk(sk), BPF_SOCK_OPS_RTT_CB_FLAG))
if (BPF_SOCK_OPS_TEST_FLAG(tp, BPF_SOCK_OPS_RTT_CB_FLAG))
tcp_call_bpf(sk, BPF_SOCK_OPS_RTT_CB, 0, NULL); tcp_call_bpf(sk, BPF_SOCK_OPS_RTT_CB, 0, NULL);
} }
......
...@@ -67,6 +67,8 @@ struct xdp_sock { ...@@ -67,6 +67,8 @@ struct xdp_sock {
* in the SKB destructor callback. * in the SKB destructor callback.
*/ */
spinlock_t tx_completion_lock; spinlock_t tx_completion_lock;
/* Protects generic receive. */
spinlock_t rx_lock;
u64 rx_dropped; u64 rx_dropped;
}; };
......
...@@ -3247,7 +3247,7 @@ struct bpf_sock_addr { ...@@ -3247,7 +3247,7 @@ struct bpf_sock_addr {
__u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write. __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. __u32 user_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 user_port; /* Allows 4-byte read and write. __u32 user_port; /* Allows 4-byte read and write.
...@@ -3256,10 +3256,10 @@ struct bpf_sock_addr { ...@@ -3256,10 +3256,10 @@ struct bpf_sock_addr {
__u32 family; /* Allows 4-byte read, but no write */ __u32 family; /* Allows 4-byte read, but no write */
__u32 type; /* Allows 4-byte read, but no write */ __u32 type; /* Allows 4-byte read, but no write */
__u32 protocol; /* Allows 4-byte read, but no write */ __u32 protocol; /* Allows 4-byte read, but no write */
__u32 msg_src_ip4; /* Allows 1,2,4-byte read an 4-byte write. __u32 msg_src_ip4; /* Allows 1,2,4-byte read and 4-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. __u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__bpf_md_ptr(struct bpf_sock *, sk); __bpf_md_ptr(struct bpf_sock *, sk);
......
...@@ -939,6 +939,7 @@ int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head, ...@@ -939,6 +939,7 @@ int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head,
} }
EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl); EXPORT_SYMBOL(__cgroup_bpf_run_filter_sysctl);
#ifdef CONFIG_NET
static bool __cgroup_bpf_prog_array_is_empty(struct cgroup *cgrp, static bool __cgroup_bpf_prog_array_is_empty(struct cgroup *cgrp,
enum bpf_attach_type attach_type) enum bpf_attach_type attach_type)
{ {
...@@ -1120,6 +1121,7 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level, ...@@ -1120,6 +1121,7 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
return ret; return ret;
} }
EXPORT_SYMBOL(__cgroup_bpf_run_filter_getsockopt); EXPORT_SYMBOL(__cgroup_bpf_run_filter_getsockopt);
#endif
static ssize_t sysctl_cpy_dir(const struct ctl_dir *dir, char **bufp, static ssize_t sysctl_cpy_dir(const struct ctl_dir *dir, char **bufp,
size_t *lenp) size_t *lenp)
...@@ -1386,10 +1388,12 @@ static const struct bpf_func_proto * ...@@ -1386,10 +1388,12 @@ static const struct bpf_func_proto *
cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{ {
switch (func_id) { switch (func_id) {
#ifdef CONFIG_NET
case BPF_FUNC_sk_storage_get: case BPF_FUNC_sk_storage_get:
return &bpf_sk_storage_get_proto; return &bpf_sk_storage_get_proto;
case BPF_FUNC_sk_storage_delete: case BPF_FUNC_sk_storage_delete:
return &bpf_sk_storage_delete_proto; return &bpf_sk_storage_delete_proto;
#endif
#ifdef CONFIG_INET #ifdef CONFIG_INET
case BPF_FUNC_tcp_sock: case BPF_FUNC_tcp_sock:
return &bpf_tcp_sock_proto; return &bpf_tcp_sock_proto;
......
...@@ -6890,6 +6890,16 @@ static bool sock_addr_is_valid_access(int off, int size, ...@@ -6890,6 +6890,16 @@ static bool sock_addr_is_valid_access(int off, int size,
if (!bpf_ctx_narrow_access_ok(off, size, size_default)) if (!bpf_ctx_narrow_access_ok(off, size, size_default))
return false; return false;
} else { } else {
if (bpf_ctx_wide_store_ok(off, size,
struct bpf_sock_addr,
user_ip6))
return true;
if (bpf_ctx_wide_store_ok(off, size,
struct bpf_sock_addr,
msg_src_ip6))
return true;
if (size != size_default) if (size != size_default)
return false; return false;
} }
...@@ -7730,9 +7740,6 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type, ...@@ -7730,9 +7740,6 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type,
/* SOCK_ADDR_STORE_NESTED_FIELD_OFF() has semantic similar to /* SOCK_ADDR_STORE_NESTED_FIELD_OFF() has semantic similar to
* SOCK_ADDR_LOAD_NESTED_FIELD_SIZE_OFF() but for store operation. * SOCK_ADDR_LOAD_NESTED_FIELD_SIZE_OFF() but for store operation.
* *
* It doesn't support SIZE argument though since narrow stores are not
* supported for now.
*
* In addition it uses Temporary Field TF (member of struct S) as the 3rd * In addition it uses Temporary Field TF (member of struct S) as the 3rd
* "register" since two registers available in convert_ctx_access are not * "register" since two registers available in convert_ctx_access are not
* enough: we can't override neither SRC, since it contains value to store, nor * enough: we can't override neither SRC, since it contains value to store, nor
...@@ -7740,7 +7747,7 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type, ...@@ -7740,7 +7747,7 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type,
* instructions. But we need a temporary place to save pointer to nested * instructions. But we need a temporary place to save pointer to nested
* structure whose field we want to store to. * structure whose field we want to store to.
*/ */
#define SOCK_ADDR_STORE_NESTED_FIELD_OFF(S, NS, F, NF, OFF, TF) \ #define SOCK_ADDR_STORE_NESTED_FIELD_OFF(S, NS, F, NF, SIZE, OFF, TF) \
do { \ do { \
int tmp_reg = BPF_REG_9; \ int tmp_reg = BPF_REG_9; \
if (si->src_reg == tmp_reg || si->dst_reg == tmp_reg) \ if (si->src_reg == tmp_reg || si->dst_reg == tmp_reg) \
...@@ -7751,8 +7758,7 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type, ...@@ -7751,8 +7758,7 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type,
offsetof(S, TF)); \ offsetof(S, TF)); \
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(S, F), tmp_reg, \ *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(S, F), tmp_reg, \
si->dst_reg, offsetof(S, F)); \ si->dst_reg, offsetof(S, F)); \
*insn++ = BPF_STX_MEM( \ *insn++ = BPF_STX_MEM(SIZE, tmp_reg, si->src_reg, \
BPF_FIELD_SIZEOF(NS, NF), tmp_reg, si->src_reg, \
bpf_target_off(NS, NF, FIELD_SIZEOF(NS, NF), \ bpf_target_off(NS, NF, FIELD_SIZEOF(NS, NF), \
target_size) \ target_size) \
+ OFF); \ + OFF); \
...@@ -7764,8 +7770,8 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type, ...@@ -7764,8 +7770,8 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type,
TF) \ TF) \
do { \ do { \
if (type == BPF_WRITE) { \ if (type == BPF_WRITE) { \
SOCK_ADDR_STORE_NESTED_FIELD_OFF(S, NS, F, NF, OFF, \ SOCK_ADDR_STORE_NESTED_FIELD_OFF(S, NS, F, NF, SIZE, \
TF); \ OFF, TF); \
} else { \ } else { \
SOCK_ADDR_LOAD_NESTED_FIELD_SIZE_OFF( \ SOCK_ADDR_LOAD_NESTED_FIELD_SIZE_OFF( \
S, NS, F, NF, SIZE, OFF); \ S, NS, F, NF, SIZE, OFF); \
......
...@@ -129,13 +129,17 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) ...@@ -129,13 +129,17 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
u64 addr; u64 addr;
int err; int err;
if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index) spin_lock_bh(&xs->rx_lock);
return -EINVAL;
if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index) {
err = -EINVAL;
goto out_unlock;
}
if (!xskq_peek_addr(xs->umem->fq, &addr) || if (!xskq_peek_addr(xs->umem->fq, &addr) ||
len > xs->umem->chunk_size_nohr - XDP_PACKET_HEADROOM) { len > xs->umem->chunk_size_nohr - XDP_PACKET_HEADROOM) {
xs->rx_dropped++; err = -ENOSPC;
return -ENOSPC; goto out_drop;
} }
addr += xs->umem->headroom; addr += xs->umem->headroom;
...@@ -144,13 +148,21 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp) ...@@ -144,13 +148,21 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
memcpy(buffer, xdp->data_meta, len + metalen); memcpy(buffer, xdp->data_meta, len + metalen);
addr += metalen; addr += metalen;
err = xskq_produce_batch_desc(xs->rx, addr, len); err = xskq_produce_batch_desc(xs->rx, addr, len);
if (!err) { if (err)
xskq_discard_addr(xs->umem->fq); goto out_drop;
xsk_flush(xs);
return 0; xskq_discard_addr(xs->umem->fq);
} xskq_produce_flush_desc(xs->rx);
spin_unlock_bh(&xs->rx_lock);
xs->sk.sk_data_ready(&xs->sk);
return 0;
out_drop:
xs->rx_dropped++; xs->rx_dropped++;
out_unlock:
spin_unlock_bh(&xs->rx_lock);
return err; return err;
} }
...@@ -787,6 +799,7 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol, ...@@ -787,6 +799,7 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
xs = xdp_sk(sk); xs = xdp_sk(sk);
mutex_init(&xs->mutex); mutex_init(&xs->mutex);
spin_lock_init(&xs->rx_lock);
spin_lock_init(&xs->tx_completion_lock); spin_lock_init(&xs->tx_completion_lock);
mutex_lock(&net->xdp.lock); mutex_lock(&net->xdp.lock);
......
...@@ -29,6 +29,7 @@ PROG COMMANDS ...@@ -29,6 +29,7 @@ PROG COMMANDS
| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*]
| **bpftool** **prog tracelog** | **bpftool** **prog tracelog**
| **bpftool** **prog run** *PROG* **data_in** *FILE* [**data_out** *FILE* [**data_size_out** *L*]] [**ctx_in** *FILE* [**ctx_out** *FILE* [**ctx_size_out** *M*]]] [**repeat** *N*]
| **bpftool** **prog help** | **bpftool** **prog help**
| |
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
...@@ -146,6 +147,39 @@ DESCRIPTION ...@@ -146,6 +147,39 @@ DESCRIPTION
streaming data from BPF programs to user space, one can use streaming data from BPF programs to user space, one can use
perf events (see also **bpftool-map**\ (8)). perf events (see also **bpftool-map**\ (8)).
**bpftool prog run** *PROG* **data_in** *FILE* [**data_out** *FILE* [**data_size_out** *L*]] [**ctx_in** *FILE* [**ctx_out** *FILE* [**ctx_size_out** *M*]]] [**repeat** *N*]
Run BPF program *PROG* in the kernel testing infrastructure
for BPF, meaning that the program works on the data and
context provided by the user, and not on actual packets or
monitored functions etc. Return value and duration for the
test run are printed out to the console.
Input data is read from the *FILE* passed with **data_in**.
If this *FILE* is "**-**", input data is read from standard
input. Input context, if any, is read from *FILE* passed with
**ctx_in**. Again, "**-**" can be used to read from standard
input, but only if standard input is not already in use for
input data. If a *FILE* is passed with **data_out**, output
data is written to that file. Similarly, output context is
written to the *FILE* passed with **ctx_out**. For both
output flows, "**-**" can be used to print to the standard
output (as plain text, or JSON if relevant option was
passed). If output keywords are omitted, output data and
context are discarded. Keywords **data_size_out** and
**ctx_size_out** are used to pass the size (in bytes) for the
output buffers to the kernel, although the default of 32 kB
should be more than enough for most cases.
Keyword **repeat** is used to indicate the number of
consecutive runs to perform. Note that output data and
context printed to files correspond to the last of those
runs. The duration printed out at the end of the runs is an
average over all runs performed by the command.
Not all program types support test run. Among those which do,
not all of them can take the **ctx_in**/**ctx_out**
arguments. bpftool does not perform checks on program types.
**bpftool prog help** **bpftool prog help**
Print short help message. Print short help message.
......
...@@ -342,6 +342,13 @@ _bpftool() ...@@ -342,6 +342,13 @@ _bpftool()
load|loadall) load|loadall)
local obj local obj
# Propose "load/loadall" to complete "bpftool prog load",
# or bash tries to complete "load" as a filename below.
if [[ ${#words[@]} -eq 3 ]]; then
COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
return 0
fi
if [[ ${#words[@]} -lt 6 ]]; then if [[ ${#words[@]} -lt 6 ]]; then
_filedir _filedir
return 0 return 0
...@@ -408,10 +415,34 @@ _bpftool() ...@@ -408,10 +415,34 @@ _bpftool()
tracelog) tracelog)
return 0 return 0
;; ;;
run)
if [[ ${#words[@]} -lt 5 ]]; then
_filedir
return 0
fi
case $prev in
id)
_bpftool_get_prog_ids
return 0
;;
data_in|data_out|ctx_in|ctx_out)
_filedir
return 0
;;
repeat|data_size_out|ctx_size_out)
return 0
;;
*)
_bpftool_once_attr 'data_in data_out data_size_out \
ctx_in ctx_out ctx_size_out repeat'
return 0
;;
esac
;;
*) *)
[[ $prev == $object ]] && \ [[ $prev == $object ]] && \
COMPREPLY=( $( compgen -W 'dump help pin attach detach load \ COMPREPLY=( $( compgen -W 'dump help pin attach detach \
show list tracelog' -- "$cur" ) ) load loadall show list tracelog run' -- "$cur" ) )
;; ;;
esac esac
;; ;;
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* Licensed under the GNU General Public License, version 2.0 (GPLv2) * Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/ */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
...@@ -44,11 +46,13 @@ static int fprintf_json(void *out, const char *fmt, ...) ...@@ -44,11 +46,13 @@ static int fprintf_json(void *out, const char *fmt, ...)
char *s; char *s;
va_start(ap, fmt); va_start(ap, fmt);
if (vasprintf(&s, fmt, ap) < 0)
return -1;
va_end(ap);
if (!oper_count) { if (!oper_count) {
int i; int i;
s = va_arg(ap, char *);
/* Strip trailing spaces */ /* Strip trailing spaces */
i = strlen(s) - 1; i = strlen(s) - 1;
while (s[i] == ' ') while (s[i] == ' ')
...@@ -61,11 +65,10 @@ static int fprintf_json(void *out, const char *fmt, ...) ...@@ -61,11 +65,10 @@ static int fprintf_json(void *out, const char *fmt, ...)
} else if (!strcmp(fmt, ",")) { } else if (!strcmp(fmt, ",")) {
/* Skip */ /* Skip */
} else { } else {
s = va_arg(ap, char *);
jsonw_string(json_wtr, s); jsonw_string(json_wtr, s);
oper_count++; oper_count++;
} }
va_end(ap); free(s);
return 0; return 0;
} }
......
...@@ -117,6 +117,35 @@ bool is_prefix(const char *pfx, const char *str) ...@@ -117,6 +117,35 @@ bool is_prefix(const char *pfx, const char *str)
return !memcmp(str, pfx, strlen(pfx)); return !memcmp(str, pfx, strlen(pfx));
} }
/* Last argument MUST be NULL pointer */
int detect_common_prefix(const char *arg, ...)
{
unsigned int count = 0;
const char *ref;
char msg[256];
va_list ap;
snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg);
va_start(ap, arg);
while ((ref = va_arg(ap, const char *))) {
if (!is_prefix(arg, ref))
continue;
count++;
if (count > 1)
strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1);
strncat(msg, ref, sizeof(msg) - strlen(msg) - 1);
}
va_end(ap);
strncat(msg, "'", sizeof(msg) - strlen(msg) - 1);
if (count >= 2) {
p_err(msg);
return -1;
}
return 0;
}
void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
{ {
unsigned char *data = arg; unsigned char *data = arg;
......
...@@ -101,6 +101,7 @@ void p_err(const char *fmt, ...); ...@@ -101,6 +101,7 @@ void p_err(const char *fmt, ...);
void p_info(const char *fmt, ...); void p_info(const char *fmt, ...);
bool is_prefix(const char *pfx, const char *str); bool is_prefix(const char *pfx, const char *str);
int detect_common_prefix(const char *arg, ...);
void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep); void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
void usage(void) __noreturn; void usage(void) __noreturn;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define MMAP_PAGE_CNT 16 #define MMAP_PAGE_CNT 16
static bool stop; static volatile bool stop;
struct event_ring_info { struct event_ring_info {
int fd; int fd;
...@@ -44,32 +44,44 @@ struct perf_event_sample { ...@@ -44,32 +44,44 @@ struct perf_event_sample {
unsigned char data[]; unsigned char data[];
}; };
struct perf_event_lost {
struct perf_event_header header;
__u64 id;
__u64 lost;
};
static void int_exit(int signo) static void int_exit(int signo)
{ {
fprintf(stderr, "Stopping...\n"); fprintf(stderr, "Stopping...\n");
stop = true; stop = true;
} }
struct event_pipe_ctx {
bool all_cpus;
int cpu;
int idx;
};
static enum bpf_perf_event_ret static enum bpf_perf_event_ret
print_bpf_output(struct perf_event_header *event, void *private_data) print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
{ {
struct perf_event_sample *e = container_of(event, struct perf_event_sample, struct perf_event_sample *e = container_of(event,
struct perf_event_sample,
header); header);
struct event_ring_info *ring = private_data; struct perf_event_lost *lost = container_of(event,
struct { struct perf_event_lost,
struct perf_event_header header; header);
__u64 id; struct event_pipe_ctx *ctx = private_data;
__u64 lost; int idx = ctx->all_cpus ? cpu : ctx->idx;
} *lost = (typeof(lost))event;
if (json_output) { if (json_output) {
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
jsonw_name(json_wtr, "type"); jsonw_name(json_wtr, "type");
jsonw_uint(json_wtr, e->header.type); jsonw_uint(json_wtr, e->header.type);
jsonw_name(json_wtr, "cpu"); jsonw_name(json_wtr, "cpu");
jsonw_uint(json_wtr, ring->cpu); jsonw_uint(json_wtr, cpu);
jsonw_name(json_wtr, "index"); jsonw_name(json_wtr, "index");
jsonw_uint(json_wtr, ring->key); jsonw_uint(json_wtr, idx);
if (e->header.type == PERF_RECORD_SAMPLE) { if (e->header.type == PERF_RECORD_SAMPLE) {
jsonw_name(json_wtr, "timestamp"); jsonw_name(json_wtr, "timestamp");
jsonw_uint(json_wtr, e->time); jsonw_uint(json_wtr, e->time);
...@@ -89,7 +101,7 @@ print_bpf_output(struct perf_event_header *event, void *private_data) ...@@ -89,7 +101,7 @@ print_bpf_output(struct perf_event_header *event, void *private_data)
if (e->header.type == PERF_RECORD_SAMPLE) { if (e->header.type == PERF_RECORD_SAMPLE) {
printf("== @%lld.%09lld CPU: %d index: %d =====\n", printf("== @%lld.%09lld CPU: %d index: %d =====\n",
e->time / 1000000000ULL, e->time % 1000000000ULL, e->time / 1000000000ULL, e->time % 1000000000ULL,
ring->cpu, ring->key); cpu, idx);
fprint_hex(stdout, e->data, e->size, " "); fprint_hex(stdout, e->data, e->size, " ");
printf("\n"); printf("\n");
} else if (e->header.type == PERF_RECORD_LOST) { } else if (e->header.type == PERF_RECORD_LOST) {
...@@ -103,87 +115,25 @@ print_bpf_output(struct perf_event_header *event, void *private_data) ...@@ -103,87 +115,25 @@ print_bpf_output(struct perf_event_header *event, void *private_data)
return LIBBPF_PERF_EVENT_CONT; return LIBBPF_PERF_EVENT_CONT;
} }
static void int do_event_pipe(int argc, char **argv)
perf_event_read(struct event_ring_info *ring, void **buf, size_t *buf_len)
{
enum bpf_perf_event_ret ret;
ret = bpf_perf_event_read_simple(ring->mem,
MMAP_PAGE_CNT * get_page_size(),
get_page_size(), buf, buf_len,
print_bpf_output, ring);
if (ret != LIBBPF_PERF_EVENT_CONT) {
fprintf(stderr, "perf read loop failed with %d\n", ret);
stop = true;
}
}
static int perf_mmap_size(void)
{
return get_page_size() * (MMAP_PAGE_CNT + 1);
}
static void *perf_event_mmap(int fd)
{
int mmap_size = perf_mmap_size();
void *base;
base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) {
p_err("event mmap failed: %s\n", strerror(errno));
return NULL;
}
return base;
}
static void perf_event_unmap(void *mem)
{
if (munmap(mem, perf_mmap_size()))
fprintf(stderr, "Can't unmap ring memory!\n");
}
static int bpf_perf_event_open(int map_fd, int key, int cpu)
{ {
struct perf_event_attr attr = { struct perf_event_attr perf_attr = {
.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME, .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME,
.type = PERF_TYPE_SOFTWARE, .type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_BPF_OUTPUT, .config = PERF_COUNT_SW_BPF_OUTPUT,
.sample_period = 1,
.wakeup_events = 1,
}; };
int pmu_fd;
pmu_fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
if (pmu_fd < 0) {
p_err("failed to open perf event %d for CPU %d", key, cpu);
return -1;
}
if (bpf_map_update_elem(map_fd, &key, &pmu_fd, BPF_ANY)) {
p_err("failed to update map for event %d for CPU %d", key, cpu);
goto err_close;
}
if (ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) {
p_err("failed to enable event %d for CPU %d", key, cpu);
goto err_close;
}
return pmu_fd;
err_close:
close(pmu_fd);
return -1;
}
int do_event_pipe(int argc, char **argv)
{
int i, nfds, map_fd, index = -1, cpu = -1;
struct bpf_map_info map_info = {}; struct bpf_map_info map_info = {};
struct event_ring_info *rings; struct perf_buffer_raw_opts opts = {};
size_t tmp_buf_sz = 0; struct event_pipe_ctx ctx = {
void *tmp_buf = NULL; .all_cpus = true,
struct pollfd *pfds; .cpu = -1,
.idx = -1,
};
struct perf_buffer *pb;
__u32 map_info_len; __u32 map_info_len;
bool do_all = true; int err, map_fd;
map_info_len = sizeof(map_info); map_info_len = sizeof(map_info);
map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len); map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len);
...@@ -205,7 +155,7 @@ int do_event_pipe(int argc, char **argv) ...@@ -205,7 +155,7 @@ int do_event_pipe(int argc, char **argv)
char *endptr; char *endptr;
NEXT_ARG(); NEXT_ARG();
cpu = strtoul(*argv, &endptr, 0); ctx.cpu = strtoul(*argv, &endptr, 0);
if (*endptr) { if (*endptr) {
p_err("can't parse %s as CPU ID", **argv); p_err("can't parse %s as CPU ID", **argv);
goto err_close_map; goto err_close_map;
...@@ -216,7 +166,7 @@ int do_event_pipe(int argc, char **argv) ...@@ -216,7 +166,7 @@ int do_event_pipe(int argc, char **argv)
char *endptr; char *endptr;
NEXT_ARG(); NEXT_ARG();
index = strtoul(*argv, &endptr, 0); ctx.idx = strtoul(*argv, &endptr, 0);
if (*endptr) { if (*endptr) {
p_err("can't parse %s as index", **argv); p_err("can't parse %s as index", **argv);
goto err_close_map; goto err_close_map;
...@@ -228,45 +178,32 @@ int do_event_pipe(int argc, char **argv) ...@@ -228,45 +178,32 @@ int do_event_pipe(int argc, char **argv)
goto err_close_map; goto err_close_map;
} }
do_all = false; ctx.all_cpus = false;
} }
if (!do_all) { if (!ctx.all_cpus) {
if (index == -1 || cpu == -1) { if (ctx.idx == -1 || ctx.cpu == -1) {
p_err("cpu and index must be specified together"); p_err("cpu and index must be specified together");
goto err_close_map; goto err_close_map;
} }
nfds = 1;
} else { } else {
nfds = min(get_possible_cpus(), map_info.max_entries); ctx.cpu = 0;
cpu = 0; ctx.idx = 0;
index = 0;
} }
rings = calloc(nfds, sizeof(rings[0])); opts.attr = &perf_attr;
if (!rings) opts.event_cb = print_bpf_output;
opts.ctx = &ctx;
opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
opts.cpus = &ctx.cpu;
opts.map_keys = &ctx.idx;
pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &opts);
err = libbpf_get_error(pb);
if (err) {
p_err("failed to create perf buffer: %s (%d)",
strerror(err), err);
goto err_close_map; goto err_close_map;
pfds = calloc(nfds, sizeof(pfds[0]));
if (!pfds)
goto err_free_rings;
for (i = 0; i < nfds; i++) {
rings[i].cpu = cpu + i;
rings[i].key = index + i;
rings[i].fd = bpf_perf_event_open(map_fd, rings[i].key,
rings[i].cpu);
if (rings[i].fd < 0)
goto err_close_fds_prev;
rings[i].mem = perf_event_mmap(rings[i].fd);
if (!rings[i].mem)
goto err_close_fds_current;
pfds[i].fd = rings[i].fd;
pfds[i].events = POLLIN;
} }
signal(SIGINT, int_exit); signal(SIGINT, int_exit);
...@@ -277,34 +214,24 @@ int do_event_pipe(int argc, char **argv) ...@@ -277,34 +214,24 @@ int do_event_pipe(int argc, char **argv)
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
while (!stop) { while (!stop) {
poll(pfds, nfds, 200); err = perf_buffer__poll(pb, 200);
for (i = 0; i < nfds; i++) if (err < 0 && err != -EINTR) {
perf_event_read(&rings[i], &tmp_buf, &tmp_buf_sz); p_err("perf buffer polling failed: %s (%d)",
strerror(err), err);
goto err_close_pb;
}
} }
free(tmp_buf);
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
for (i = 0; i < nfds; i++) { perf_buffer__free(pb);
perf_event_unmap(rings[i].mem);
close(rings[i].fd);
}
free(pfds);
free(rings);
close(map_fd); close(map_fd);
return 0; return 0;
err_close_fds_prev: err_close_pb:
while (i--) { perf_buffer__free(pb);
perf_event_unmap(rings[i].mem);
err_close_fds_current:
close(rings[i].fd);
}
free(pfds);
err_free_rings:
free(rings);
err_close_map: err_close_map:
close(map_fd); close(map_fd);
return -1; return -1;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/sizes.h>
#include <bpf.h> #include <bpf.h>
#include <btf.h> #include <btf.h>
...@@ -748,6 +749,344 @@ static int do_detach(int argc, char **argv) ...@@ -748,6 +749,344 @@ static int do_detach(int argc, char **argv)
return 0; return 0;
} }
static int check_single_stdin(char *file_data_in, char *file_ctx_in)
{
if (file_data_in && file_ctx_in &&
!strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) {
p_err("cannot use standard input for both data_in and ctx_in");
return -1;
}
return 0;
}
static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
{
size_t block_size = 256;
size_t buf_size = block_size;
size_t nb_read = 0;
void *tmp;
FILE *f;
if (!fname) {
*data_ptr = NULL;
*size = 0;
return 0;
}
if (!strcmp(fname, "-"))
f = stdin;
else
f = fopen(fname, "r");
if (!f) {
p_err("failed to open %s: %s", fname, strerror(errno));
return -1;
}
*data_ptr = malloc(block_size);
if (!*data_ptr) {
p_err("failed to allocate memory for data_in/ctx_in: %s",
strerror(errno));
goto err_fclose;
}
while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) {
if (feof(f))
break;
if (ferror(f)) {
p_err("failed to read data_in/ctx_in from %s: %s",
fname, strerror(errno));
goto err_free;
}
if (nb_read > buf_size - block_size) {
if (buf_size == UINT32_MAX) {
p_err("data_in/ctx_in is too long (max: %d)",
UINT32_MAX);
goto err_free;
}
/* No space for fread()-ing next chunk; realloc() */
buf_size *= 2;
tmp = realloc(*data_ptr, buf_size);
if (!tmp) {
p_err("failed to reallocate data_in/ctx_in: %s",
strerror(errno));
goto err_free;
}
*data_ptr = tmp;
}
}
if (f != stdin)
fclose(f);
*size = nb_read;
return 0;
err_free:
free(*data_ptr);
*data_ptr = NULL;
err_fclose:
if (f != stdin)
fclose(f);
return -1;
}
static void hex_print(void *data, unsigned int size, FILE *f)
{
size_t i, j;
char c;
for (i = 0; i < size; i += 16) {
/* Row offset */
fprintf(f, "%07zx\t", i);
/* Hexadecimal values */
for (j = i; j < i + 16 && j < size; j++)
fprintf(f, "%02x%s", *(uint8_t *)(data + j),
j % 2 ? " " : "");
for (; j < i + 16; j++)
fprintf(f, " %s", j % 2 ? " " : "");
/* ASCII values (if relevant), '.' otherwise */
fprintf(f, "| ");
for (j = i; j < i + 16 && j < size; j++) {
c = *(char *)(data + j);
if (c < ' ' || c > '~')
c = '.';
fprintf(f, "%c%s", c, j == i + 7 ? " " : "");
}
fprintf(f, "\n");
}
}
static int
print_run_output(void *data, unsigned int size, const char *fname,
const char *json_key)
{
size_t nb_written;
FILE *f;
if (!fname)
return 0;
if (!strcmp(fname, "-")) {
f = stdout;
if (json_output) {
jsonw_name(json_wtr, json_key);
print_data_json(data, size);
} else {
hex_print(data, size, f);
}
return 0;
}
f = fopen(fname, "w");
if (!f) {
p_err("failed to open %s: %s", fname, strerror(errno));
return -1;
}
nb_written = fwrite(data, 1, size, f);
fclose(f);
if (nb_written != size) {
p_err("failed to write output data/ctx: %s", strerror(errno));
return -1;
}
return 0;
}
static int alloc_run_data(void **data_ptr, unsigned int size_out)
{
*data_ptr = calloc(size_out, 1);
if (!*data_ptr) {
p_err("failed to allocate memory for output data/ctx: %s",
strerror(errno));
return -1;
}
return 0;
}
static int do_run(int argc, char **argv)
{
char *data_fname_in = NULL, *data_fname_out = NULL;
char *ctx_fname_in = NULL, *ctx_fname_out = NULL;
struct bpf_prog_test_run_attr test_attr = {0};
const unsigned int default_size = SZ_32K;
void *data_in = NULL, *data_out = NULL;
void *ctx_in = NULL, *ctx_out = NULL;
unsigned int repeat = 1;
int fd, err;
if (!REQ_ARGS(4))
return -1;
fd = prog_parse_fd(&argc, &argv);
if (fd < 0)
return -1;
while (argc) {
if (detect_common_prefix(*argv, "data_in", "data_out",
"data_size_out", NULL))
return -1;
if (detect_common_prefix(*argv, "ctx_in", "ctx_out",
"ctx_size_out", NULL))
return -1;
if (is_prefix(*argv, "data_in")) {
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
data_fname_in = GET_ARG();
if (check_single_stdin(data_fname_in, ctx_fname_in))
return -1;
} else if (is_prefix(*argv, "data_out")) {
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
data_fname_out = GET_ARG();
} else if (is_prefix(*argv, "data_size_out")) {
char *endptr;
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
test_attr.data_size_out = strtoul(*argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as output data size",
*argv);
return -1;
}
NEXT_ARG();
} else if (is_prefix(*argv, "ctx_in")) {
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
ctx_fname_in = GET_ARG();
if (check_single_stdin(data_fname_in, ctx_fname_in))
return -1;
} else if (is_prefix(*argv, "ctx_out")) {
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
ctx_fname_out = GET_ARG();
} else if (is_prefix(*argv, "ctx_size_out")) {
char *endptr;
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
test_attr.ctx_size_out = strtoul(*argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as output context size",
*argv);
return -1;
}
NEXT_ARG();
} else if (is_prefix(*argv, "repeat")) {
char *endptr;
NEXT_ARG();
if (!REQ_ARGS(1))
return -1;
repeat = strtoul(*argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as repeat number",
*argv);
return -1;
}
NEXT_ARG();
} else {
p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?",
*argv);
return -1;
}
}
err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in);
if (err)
return -1;
if (data_in) {
if (!test_attr.data_size_out)
test_attr.data_size_out = default_size;
err = alloc_run_data(&data_out, test_attr.data_size_out);
if (err)
goto free_data_in;
}
err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in);
if (err)
goto free_data_out;
if (ctx_in) {
if (!test_attr.ctx_size_out)
test_attr.ctx_size_out = default_size;
err = alloc_run_data(&ctx_out, test_attr.ctx_size_out);
if (err)
goto free_ctx_in;
}
test_attr.prog_fd = fd;
test_attr.repeat = repeat;
test_attr.data_in = data_in;
test_attr.data_out = data_out;
test_attr.ctx_in = ctx_in;
test_attr.ctx_out = ctx_out;
err = bpf_prog_test_run_xattr(&test_attr);
if (err) {
p_err("failed to run program: %s", strerror(errno));
goto free_ctx_out;
}
err = 0;
if (json_output)
jsonw_start_object(json_wtr); /* root */
/* Do not exit on errors occurring when printing output data/context,
* we still want to print return value and duration for program run.
*/
if (test_attr.data_size_out)
err += print_run_output(test_attr.data_out,
test_attr.data_size_out,
data_fname_out, "data_out");
if (test_attr.ctx_size_out)
err += print_run_output(test_attr.ctx_out,
test_attr.ctx_size_out,
ctx_fname_out, "ctx_out");
if (json_output) {
jsonw_uint_field(json_wtr, "retval", test_attr.retval);
jsonw_uint_field(json_wtr, "duration", test_attr.duration);
jsonw_end_object(json_wtr); /* root */
} else {
fprintf(stdout, "Return value: %u, duration%s: %uns\n",
test_attr.retval,
repeat > 1 ? " (average)" : "", test_attr.duration);
}
free_ctx_out:
free(ctx_out);
free_ctx_in:
free(ctx_in);
free_data_out:
free(data_out);
free_data_in:
free(data_in);
return err;
}
static int load_with_options(int argc, char **argv, bool first_prog_only) static int load_with_options(int argc, char **argv, bool first_prog_only)
{ {
struct bpf_object_load_attr load_attr = { 0 }; struct bpf_object_load_attr load_attr = { 0 };
...@@ -1058,6 +1397,11 @@ static int do_help(int argc, char **argv) ...@@ -1058,6 +1397,11 @@ static int do_help(int argc, char **argv)
" [pinmaps MAP_DIR]\n" " [pinmaps MAP_DIR]\n"
" %s %s attach PROG ATTACH_TYPE [MAP]\n" " %s %s attach PROG ATTACH_TYPE [MAP]\n"
" %s %s detach PROG ATTACH_TYPE [MAP]\n" " %s %s detach PROG ATTACH_TYPE [MAP]\n"
" %s %s run PROG \\\n"
" data_in FILE \\\n"
" [data_out FILE [data_size_out L]] \\\n"
" [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n"
" [repeat N]\n"
" %s %s tracelog\n" " %s %s tracelog\n"
" %s %s help\n" " %s %s help\n"
"\n" "\n"
...@@ -1079,7 +1423,8 @@ static int do_help(int argc, char **argv) ...@@ -1079,7 +1423,8 @@ static int do_help(int argc, char **argv)
"", "",
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2]);
return 0; return 0;
} }
...@@ -1095,6 +1440,7 @@ static const struct cmd cmds[] = { ...@@ -1095,6 +1440,7 @@ static const struct cmd cmds[] = {
{ "attach", do_attach }, { "attach", do_attach },
{ "detach", do_detach }, { "detach", do_detach },
{ "tracelog", do_tracelog }, { "tracelog", do_tracelog },
{ "run", do_run },
{ 0 } { 0 }
}; };
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* include/linux/sizes.h
*/
#ifndef __LINUX_SIZES_H__
#define __LINUX_SIZES_H__
#include <linux/const.h>
#define SZ_1 0x00000001
#define SZ_2 0x00000002
#define SZ_4 0x00000004
#define SZ_8 0x00000008
#define SZ_16 0x00000010
#define SZ_32 0x00000020
#define SZ_64 0x00000040
#define SZ_128 0x00000080
#define SZ_256 0x00000100
#define SZ_512 0x00000200
#define SZ_1K 0x00000400
#define SZ_2K 0x00000800
#define SZ_4K 0x00001000
#define SZ_8K 0x00002000
#define SZ_16K 0x00004000
#define SZ_32K 0x00008000
#define SZ_64K 0x00010000
#define SZ_128K 0x00020000
#define SZ_256K 0x00040000
#define SZ_512K 0x00080000
#define SZ_1M 0x00100000
#define SZ_2M 0x00200000
#define SZ_4M 0x00400000
#define SZ_8M 0x00800000
#define SZ_16M 0x01000000
#define SZ_32M 0x02000000
#define SZ_64M 0x04000000
#define SZ_128M 0x08000000
#define SZ_256M 0x10000000
#define SZ_512M 0x20000000
#define SZ_1G 0x40000000
#define SZ_2G 0x80000000
#define SZ_4G _AC(0x100000000, ULL)
#endif /* __LINUX_SIZES_H__ */
...@@ -3244,7 +3244,7 @@ struct bpf_sock_addr { ...@@ -3244,7 +3244,7 @@ struct bpf_sock_addr {
__u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write. __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. __u32 user_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 user_port; /* Allows 4-byte read and write. __u32 user_port; /* Allows 4-byte read and write.
...@@ -3253,10 +3253,10 @@ struct bpf_sock_addr { ...@@ -3253,10 +3253,10 @@ struct bpf_sock_addr {
__u32 family; /* Allows 4-byte read, but no write */ __u32 family; /* Allows 4-byte read, but no write */
__u32 type; /* Allows 4-byte read, but no write */ __u32 type; /* Allows 4-byte read, but no write */
__u32 protocol; /* Allows 4-byte read, but no write */ __u32 protocol; /* Allows 4-byte read, but no write */
__u32 msg_src_ip4; /* Allows 1,2,4-byte read an 4-byte write. __u32 msg_src_ip4; /* Allows 1,2,4-byte read and 4-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. __u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
* Stored in network byte order. * Stored in network byte order.
*/ */
__bpf_md_ptr(struct bpf_sock *, sk); __bpf_md_ptr(struct bpf_sock *, sk);
......
...@@ -9,7 +9,8 @@ described here. It's recommended to follow these conventions whenever a ...@@ -9,7 +9,8 @@ described here. It's recommended to follow these conventions whenever a
new function or type is added to keep libbpf API clean and consistent. new function or type is added to keep libbpf API clean and consistent.
All types and functions provided by libbpf API should have one of the All types and functions provided by libbpf API should have one of the
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``. following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
``perf_buffer_``.
System call wrappers System call wrappers
-------------------- --------------------
......
This diff is collapsed.
...@@ -165,6 +165,27 @@ LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path); ...@@ -165,6 +165,27 @@ LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path);
LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path); LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);
LIBBPF_API void bpf_program__unload(struct bpf_program *prog); LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
struct bpf_link;
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
LIBBPF_API struct bpf_link *
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
LIBBPF_API struct bpf_link *
bpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,
const char *func_name);
LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,
pid_t pid, const char *binary_path,
size_t func_offset);
LIBBPF_API struct bpf_link *
bpf_program__attach_tracepoint(struct bpf_program *prog,
const char *tp_category,
const char *tp_name);
LIBBPF_API struct bpf_link *
bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
const char *tp_name);
struct bpf_insn; struct bpf_insn;
/* /*
...@@ -337,6 +358,26 @@ LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type, ...@@ -337,6 +358,26 @@ LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags); LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
struct perf_buffer;
typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
void *data, __u32 size);
typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
/* common use perf buffer options */
struct perf_buffer_opts {
/* if specified, sample_cb is called for each sample */
perf_buffer_sample_fn sample_cb;
/* if specified, lost_cb is called for each batch of lost samples */
perf_buffer_lost_fn lost_cb;
/* ctx is provided to sample_cb and lost_cb */
void *ctx;
};
LIBBPF_API struct perf_buffer *
perf_buffer__new(int map_fd, size_t page_cnt,
const struct perf_buffer_opts *opts);
enum bpf_perf_event_ret { enum bpf_perf_event_ret {
LIBBPF_PERF_EVENT_DONE = 0, LIBBPF_PERF_EVENT_DONE = 0,
LIBBPF_PERF_EVENT_ERROR = -1, LIBBPF_PERF_EVENT_ERROR = -1,
...@@ -344,6 +385,35 @@ enum bpf_perf_event_ret { ...@@ -344,6 +385,35 @@ enum bpf_perf_event_ret {
}; };
struct perf_event_header; struct perf_event_header;
typedef enum bpf_perf_event_ret
(*perf_buffer_event_fn)(void *ctx, int cpu, struct perf_event_header *event);
/* raw perf buffer options, giving most power and control */
struct perf_buffer_raw_opts {
/* perf event attrs passed directly into perf_event_open() */
struct perf_event_attr *attr;
/* raw event callback */
perf_buffer_event_fn event_cb;
/* ctx is provided to event_cb */
void *ctx;
/* if cpu_cnt == 0, open all on all possible CPUs (up to the number of
* max_entries of given PERF_EVENT_ARRAY map)
*/
int cpu_cnt;
/* if cpu_cnt > 0, cpus is an array of CPUs to open ring buffers on */
int *cpus;
/* if cpu_cnt > 0, map_keys specify map keys to set per-CPU FDs for */
int *map_keys;
};
LIBBPF_API struct perf_buffer *
perf_buffer__new_raw(int map_fd, size_t page_cnt,
const struct perf_buffer_raw_opts *opts);
LIBBPF_API void perf_buffer__free(struct perf_buffer *pb);
LIBBPF_API int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms);
typedef enum bpf_perf_event_ret typedef enum bpf_perf_event_ret
(*bpf_perf_event_print_t)(struct perf_event_header *hdr, (*bpf_perf_event_print_t)(struct perf_event_header *hdr,
void *private_data); void *private_data);
......
...@@ -167,10 +167,20 @@ LIBBPF_0.0.3 { ...@@ -167,10 +167,20 @@ LIBBPF_0.0.3 {
LIBBPF_0.0.4 { LIBBPF_0.0.4 {
global: global:
bpf_link__destroy;
bpf_object__load_xattr;
bpf_program__attach_kprobe;
bpf_program__attach_perf_event;
bpf_program__attach_raw_tracepoint;
bpf_program__attach_tracepoint;
bpf_program__attach_uprobe;
btf_dump__dump_type; btf_dump__dump_type;
btf_dump__free; btf_dump__free;
btf_dump__new; btf_dump__new;
btf__parse_elf; btf__parse_elf;
bpf_object__load_xattr;
libbpf_num_possible_cpus; libbpf_num_possible_cpus;
perf_buffer__free;
perf_buffer__new;
perf_buffer__new_raw;
perf_buffer__poll;
} LIBBPF_0.0.3; } LIBBPF_0.0.3;
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
char *libbpf_strerror_r(int err, char *dst, int len) char *libbpf_strerror_r(int err, char *dst, int len)
{ {
int ret = strerror_r(err, dst, len); int ret = strerror_r(err < 0 ? -err : err, dst, len);
if (ret) if (ret)
snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret); snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret);
return dst; return dst;
......
...@@ -42,3 +42,4 @@ xdping ...@@ -42,3 +42,4 @@ xdping
test_sockopt test_sockopt
test_sockopt_sk test_sockopt_sk
test_sockopt_multi test_sockopt_multi
test_tcp_rtt
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
*/ */
#define SEC(NAME) __attribute__((section(NAME), used)) #define SEC(NAME) __attribute__((section(NAME), used))
#define __uint(name, val) int (*name)[val]
#define __type(name, val) val *name
/* helper macro to print out debug messages */ /* helper macro to print out debug messages */
#define bpf_printk(fmt, ...) \ #define bpf_printk(fmt, ...) \
({ \ ({ \
......
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
ssize_t get_base_addr() {
size_t start;
char buf[256];
FILE *f;
f = fopen("/proc/self/maps", "r");
if (!f)
return -errno;
while (fscanf(f, "%zx-%*x %s %*s\n", &start, buf) == 2) {
if (strcmp(buf, "r-xp") == 0) {
fclose(f);
return start;
}
}
fclose(f);
return -EINVAL;
}
#ifdef __x86_64__
#define SYS_KPROBE_NAME "__x64_sys_nanosleep"
#else
#define SYS_KPROBE_NAME "sys_nanosleep"
#endif
void test_attach_probe(void)
{
const char *kprobe_name = "kprobe/sys_nanosleep";
const char *kretprobe_name = "kretprobe/sys_nanosleep";
const char *uprobe_name = "uprobe/trigger_func";
const char *uretprobe_name = "uretprobe/trigger_func";
const int kprobe_idx = 0, kretprobe_idx = 1;
const int uprobe_idx = 2, uretprobe_idx = 3;
const char *file = "./test_attach_probe.o";
struct bpf_program *kprobe_prog, *kretprobe_prog;
struct bpf_program *uprobe_prog, *uretprobe_prog;
struct bpf_object *obj;
int err, prog_fd, duration = 0, res;
struct bpf_link *kprobe_link = NULL;
struct bpf_link *kretprobe_link = NULL;
struct bpf_link *uprobe_link = NULL;
struct bpf_link *uretprobe_link = NULL;
int results_map_fd;
size_t uprobe_offset;
ssize_t base_addr;
base_addr = get_base_addr();
if (CHECK(base_addr < 0, "get_base_addr",
"failed to find base addr: %zd", base_addr))
return;
uprobe_offset = (size_t)&get_base_addr - base_addr;
/* load programs */
err = bpf_prog_load(file, BPF_PROG_TYPE_KPROBE, &obj, &prog_fd);
if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno))
return;
kprobe_prog = bpf_object__find_program_by_title(obj, kprobe_name);
if (CHECK(!kprobe_prog, "find_probe",
"prog '%s' not found\n", kprobe_name))
goto cleanup;
kretprobe_prog = bpf_object__find_program_by_title(obj, kretprobe_name);
if (CHECK(!kretprobe_prog, "find_probe",
"prog '%s' not found\n", kretprobe_name))
goto cleanup;
uprobe_prog = bpf_object__find_program_by_title(obj, uprobe_name);
if (CHECK(!uprobe_prog, "find_probe",
"prog '%s' not found\n", uprobe_name))
goto cleanup;
uretprobe_prog = bpf_object__find_program_by_title(obj, uretprobe_name);
if (CHECK(!uretprobe_prog, "find_probe",
"prog '%s' not found\n", uretprobe_name))
goto cleanup;
/* load maps */
results_map_fd = bpf_find_map(__func__, obj, "results_map");
if (CHECK(results_map_fd < 0, "find_results_map",
"err %d\n", results_map_fd))
goto cleanup;
kprobe_link = bpf_program__attach_kprobe(kprobe_prog,
false /* retprobe */,
SYS_KPROBE_NAME);
if (CHECK(IS_ERR(kprobe_link), "attach_kprobe",
"err %ld\n", PTR_ERR(kprobe_link))) {
kprobe_link = NULL;
goto cleanup;
}
kretprobe_link = bpf_program__attach_kprobe(kretprobe_prog,
true /* retprobe */,
SYS_KPROBE_NAME);
if (CHECK(IS_ERR(kretprobe_link), "attach_kretprobe",
"err %ld\n", PTR_ERR(kretprobe_link))) {
kretprobe_link = NULL;
goto cleanup;
}
uprobe_link = bpf_program__attach_uprobe(uprobe_prog,
false /* retprobe */,
0 /* self pid */,
"/proc/self/exe",
uprobe_offset);
if (CHECK(IS_ERR(uprobe_link), "attach_uprobe",
"err %ld\n", PTR_ERR(uprobe_link))) {
uprobe_link = NULL;
goto cleanup;
}
uretprobe_link = bpf_program__attach_uprobe(uretprobe_prog,
true /* retprobe */,
-1 /* any pid */,
"/proc/self/exe",
uprobe_offset);
if (CHECK(IS_ERR(uretprobe_link), "attach_uretprobe",
"err %ld\n", PTR_ERR(uretprobe_link))) {
uretprobe_link = NULL;
goto cleanup;
}
/* trigger & validate kprobe && kretprobe */
usleep(1);
err = bpf_map_lookup_elem(results_map_fd, &kprobe_idx, &res);
if (CHECK(err, "get_kprobe_res",
"failed to get kprobe res: %d\n", err))
goto cleanup;
if (CHECK(res != kprobe_idx + 1, "check_kprobe_res",
"wrong kprobe res: %d\n", res))
goto cleanup;
err = bpf_map_lookup_elem(results_map_fd, &kretprobe_idx, &res);
if (CHECK(err, "get_kretprobe_res",
"failed to get kretprobe res: %d\n", err))
goto cleanup;
if (CHECK(res != kretprobe_idx + 1, "check_kretprobe_res",
"wrong kretprobe res: %d\n", res))
goto cleanup;
/* trigger & validate uprobe & uretprobe */
get_base_addr();
err = bpf_map_lookup_elem(results_map_fd, &uprobe_idx, &res);
if (CHECK(err, "get_uprobe_res",
"failed to get uprobe res: %d\n", err))
goto cleanup;
if (CHECK(res != uprobe_idx + 1, "check_uprobe_res",
"wrong uprobe res: %d\n", res))
goto cleanup;
err = bpf_map_lookup_elem(results_map_fd, &uretprobe_idx, &res);
if (CHECK(err, "get_uretprobe_res",
"failed to get uretprobe res: %d\n", err))
goto cleanup;
if (CHECK(res != uretprobe_idx + 1, "check_uretprobe_res",
"wrong uretprobe res: %d\n", res))
goto cleanup;
cleanup:
bpf_link__destroy(kprobe_link);
bpf_link__destroy(kretprobe_link);
bpf_link__destroy(uprobe_link);
bpf_link__destroy(uretprobe_link);
bpf_object__close(obj);
}
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <sys/socket.h>
#include <test_progs.h>
#ifdef __x86_64__
#define SYS_KPROBE_NAME "__x64_sys_nanosleep"
#else
#define SYS_KPROBE_NAME "sys_nanosleep"
#endif
static void on_sample(void *ctx, int cpu, void *data, __u32 size)
{
int cpu_data = *(int *)data, duration = 0;
cpu_set_t *cpu_seen = ctx;
if (cpu_data != cpu)
CHECK(cpu_data != cpu, "check_cpu_data",
"cpu_data %d != cpu %d\n", cpu_data, cpu);
CPU_SET(cpu, cpu_seen);
}
void test_perf_buffer(void)
{
int err, prog_fd, nr_cpus, i, duration = 0;
const char *prog_name = "kprobe/sys_nanosleep";
const char *file = "./test_perf_buffer.o";
struct perf_buffer_opts pb_opts = {};
struct bpf_map *perf_buf_map;
cpu_set_t cpu_set, cpu_seen;
struct bpf_program *prog;
struct bpf_object *obj;
struct perf_buffer *pb;
struct bpf_link *link;
nr_cpus = libbpf_num_possible_cpus();
if (CHECK(nr_cpus < 0, "nr_cpus", "err %d\n", nr_cpus))
return;
/* load program */
err = bpf_prog_load(file, BPF_PROG_TYPE_KPROBE, &obj, &prog_fd);
if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno))
return;
prog = bpf_object__find_program_by_title(obj, prog_name);
if (CHECK(!prog, "find_probe", "prog '%s' not found\n", prog_name))
goto out_close;
/* load map */
perf_buf_map = bpf_object__find_map_by_name(obj, "perf_buf_map");
if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n"))
goto out_close;
/* attach kprobe */
link = bpf_program__attach_kprobe(prog, false /* retprobe */,
SYS_KPROBE_NAME);
if (CHECK(IS_ERR(link), "attach_kprobe", "err %ld\n", PTR_ERR(link)))
goto out_close;
/* set up perf buffer */
pb_opts.sample_cb = on_sample;
pb_opts.ctx = &cpu_seen;
pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts);
if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb)))
goto out_detach;
/* trigger kprobe on every CPU */
CPU_ZERO(&cpu_seen);
for (i = 0; i < nr_cpus; i++) {
CPU_ZERO(&cpu_set);
CPU_SET(i, &cpu_set);
err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set),
&cpu_set);
if (err && CHECK(err, "set_affinity", "cpu #%d, err %d\n",
i, err))
goto out_detach;
usleep(1);
}
/* read perf buffer */
err = perf_buffer__poll(pb, 100);
if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err))
goto out_free_pb;
if (CHECK(CPU_COUNT(&cpu_seen) != nr_cpus, "seen_cpu_cnt",
"expect %d, seen %d\n", nr_cpus, CPU_COUNT(&cpu_seen)))
goto out_free_pb;
out_free_pb:
perf_buffer__free(pb);
out_detach:
bpf_link__destroy(link);
out_close:
bpf_object__close(obj);
}
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
void test_stacktrace_build_id(void) void test_stacktrace_build_id(void)
{ {
int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd; int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd;
const char *prog_name = "tracepoint/random/urandom_read";
const char *file = "./test_stacktrace_build_id.o"; const char *file = "./test_stacktrace_build_id.o";
int bytes, efd, err, pmu_fd, prog_fd, stack_trace_len; int err, prog_fd, stack_trace_len;
struct perf_event_attr attr = {};
__u32 key, previous_key, val, duration = 0; __u32 key, previous_key, val, duration = 0;
struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
struct bpf_link *link = NULL;
char buf[256]; char buf[256];
int i, j; int i, j;
struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH];
...@@ -18,44 +20,16 @@ void test_stacktrace_build_id(void) ...@@ -18,44 +20,16 @@ void test_stacktrace_build_id(void)
retry: retry:
err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno))
goto out; return;
/* Get the ID for the sched/sched_switch tracepoint */ prog = bpf_object__find_program_by_title(obj, prog_name);
snprintf(buf, sizeof(buf), if (CHECK(!prog, "find_prog", "prog '%s' not found\n", prog_name))
"/sys/kernel/debug/tracing/events/random/urandom_read/id");
efd = open(buf, O_RDONLY, 0);
if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno))
goto close_prog; goto close_prog;
bytes = read(efd, buf, sizeof(buf)); link = bpf_program__attach_tracepoint(prog, "random", "urandom_read");
close(efd); if (CHECK(IS_ERR(link), "attach_tp", "err %ld\n", PTR_ERR(link)))
if (CHECK(bytes <= 0 || bytes >= sizeof(buf),
"read", "bytes %d errno %d\n", bytes, errno))
goto close_prog; goto close_prog;
/* Open the perf event and attach bpf progrram */
attr.config = strtol(buf, NULL, 0);
attr.type = PERF_TYPE_TRACEPOINT;
attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
attr.sample_period = 1;
attr.wakeup_events = 1;
pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
0 /* cpu 0 */, -1 /* group id */,
0 /* flags */);
if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n",
pmu_fd, errno))
goto close_prog;
err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n",
err, errno))
goto close_pmu;
err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n",
err, errno))
goto disable_pmu;
/* find map fds */ /* find map fds */
control_map_fd = bpf_find_map(__func__, obj, "control_map"); control_map_fd = bpf_find_map(__func__, obj, "control_map");
if (CHECK(control_map_fd < 0, "bpf_find_map control_map", if (CHECK(control_map_fd < 0, "bpf_find_map control_map",
...@@ -133,8 +107,7 @@ void test_stacktrace_build_id(void) ...@@ -133,8 +107,7 @@ void test_stacktrace_build_id(void)
* try it one more time. * try it one more time.
*/ */
if (build_id_matches < 1 && retry--) { if (build_id_matches < 1 && retry--) {
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); bpf_link__destroy(link);
close(pmu_fd);
bpf_object__close(obj); bpf_object__close(obj);
printf("%s:WARN:Didn't find expected build ID from the map, retrying\n", printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__); __func__);
...@@ -152,14 +125,8 @@ void test_stacktrace_build_id(void) ...@@ -152,14 +125,8 @@ void test_stacktrace_build_id(void)
"err %d errno %d\n", err, errno); "err %d errno %d\n", err, errno);
disable_pmu: disable_pmu:
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); bpf_link__destroy(link);
close_pmu:
close(pmu_fd);
close_prog: close_prog:
bpf_object__close(obj); bpf_object__close(obj);
out:
return;
} }
...@@ -17,6 +17,7 @@ static __u64 read_perf_max_sample_freq(void) ...@@ -17,6 +17,7 @@ static __u64 read_perf_max_sample_freq(void)
void test_stacktrace_build_id_nmi(void) void test_stacktrace_build_id_nmi(void)
{ {
int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd; int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd;
const char *prog_name = "tracepoint/random/urandom_read";
const char *file = "./test_stacktrace_build_id.o"; const char *file = "./test_stacktrace_build_id.o";
int err, pmu_fd, prog_fd; int err, pmu_fd, prog_fd;
struct perf_event_attr attr = { struct perf_event_attr attr = {
...@@ -25,7 +26,9 @@ void test_stacktrace_build_id_nmi(void) ...@@ -25,7 +26,9 @@ void test_stacktrace_build_id_nmi(void)
.config = PERF_COUNT_HW_CPU_CYCLES, .config = PERF_COUNT_HW_CPU_CYCLES,
}; };
__u32 key, previous_key, val, duration = 0; __u32 key, previous_key, val, duration = 0;
struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
struct bpf_link *link;
char buf[256]; char buf[256];
int i, j; int i, j;
struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH];
...@@ -39,6 +42,10 @@ void test_stacktrace_build_id_nmi(void) ...@@ -39,6 +42,10 @@ void test_stacktrace_build_id_nmi(void)
if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno))
return; return;
prog = bpf_object__find_program_by_title(obj, prog_name);
if (CHECK(!prog, "find_prog", "prog '%s' not found\n", prog_name))
goto close_prog;
pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
0 /* cpu 0 */, -1 /* group id */, 0 /* cpu 0 */, -1 /* group id */,
0 /* flags */); 0 /* flags */);
...@@ -47,15 +54,12 @@ void test_stacktrace_build_id_nmi(void) ...@@ -47,15 +54,12 @@ void test_stacktrace_build_id_nmi(void)
pmu_fd, errno)) pmu_fd, errno))
goto close_prog; goto close_prog;
err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); link = bpf_program__attach_perf_event(prog, pmu_fd);
if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", if (CHECK(IS_ERR(link), "attach_perf_event",
err, errno)) "err %ld\n", PTR_ERR(link))) {
goto close_pmu; close(pmu_fd);
goto close_prog;
err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); }
if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n",
err, errno))
goto disable_pmu;
/* find map fds */ /* find map fds */
control_map_fd = bpf_find_map(__func__, obj, "control_map"); control_map_fd = bpf_find_map(__func__, obj, "control_map");
...@@ -134,8 +138,7 @@ void test_stacktrace_build_id_nmi(void) ...@@ -134,8 +138,7 @@ void test_stacktrace_build_id_nmi(void)
* try it one more time. * try it one more time.
*/ */
if (build_id_matches < 1 && retry--) { if (build_id_matches < 1 && retry--) {
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); bpf_link__destroy(link);
close(pmu_fd);
bpf_object__close(obj); bpf_object__close(obj);
printf("%s:WARN:Didn't find expected build ID from the map, retrying\n", printf("%s:WARN:Didn't find expected build ID from the map, retrying\n",
__func__); __func__);
...@@ -154,11 +157,7 @@ void test_stacktrace_build_id_nmi(void) ...@@ -154,11 +157,7 @@ void test_stacktrace_build_id_nmi(void)
*/ */
disable_pmu: disable_pmu:
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); bpf_link__destroy(link);
close_pmu:
close(pmu_fd);
close_prog: close_prog:
bpf_object__close(obj); bpf_object__close(obj);
} }
...@@ -4,50 +4,26 @@ ...@@ -4,50 +4,26 @@
void test_stacktrace_map(void) void test_stacktrace_map(void)
{ {
int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd; int control_map_fd, stackid_hmap_fd, stackmap_fd, stack_amap_fd;
const char *prog_name = "tracepoint/sched/sched_switch";
int err, prog_fd, stack_trace_len;
const char *file = "./test_stacktrace_map.o"; const char *file = "./test_stacktrace_map.o";
int bytes, efd, err, pmu_fd, prog_fd, stack_trace_len;
struct perf_event_attr attr = {};
__u32 key, val, duration = 0; __u32 key, val, duration = 0;
struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
char buf[256]; struct bpf_link *link;
err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno))
return; return;
/* Get the ID for the sched/sched_switch tracepoint */ prog = bpf_object__find_program_by_title(obj, prog_name);
snprintf(buf, sizeof(buf), if (CHECK(!prog, "find_prog", "prog '%s' not found\n", prog_name))
"/sys/kernel/debug/tracing/events/sched/sched_switch/id");
efd = open(buf, O_RDONLY, 0);
if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno))
goto close_prog; goto close_prog;
bytes = read(efd, buf, sizeof(buf)); link = bpf_program__attach_tracepoint(prog, "sched", "sched_switch");
close(efd); if (CHECK(IS_ERR(link), "attach_tp", "err %ld\n", PTR_ERR(link)))
if (bytes <= 0 || bytes >= sizeof(buf))
goto close_prog; goto close_prog;
/* Open the perf event and attach bpf progrram */
attr.config = strtol(buf, NULL, 0);
attr.type = PERF_TYPE_TRACEPOINT;
attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
attr.sample_period = 1;
attr.wakeup_events = 1;
pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
0 /* cpu 0 */, -1 /* group id */,
0 /* flags */);
if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n",
pmu_fd, errno))
goto close_prog;
err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
if (err)
goto disable_pmu;
err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
if (err)
goto disable_pmu;
/* find map fds */ /* find map fds */
control_map_fd = bpf_find_map(__func__, obj, "control_map"); control_map_fd = bpf_find_map(__func__, obj, "control_map");
if (control_map_fd < 0) if (control_map_fd < 0)
...@@ -96,8 +72,7 @@ void test_stacktrace_map(void) ...@@ -96,8 +72,7 @@ void test_stacktrace_map(void)
disable_pmu: disable_pmu:
error_cnt++; error_cnt++;
disable_pmu_noerr: disable_pmu_noerr:
ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); bpf_link__destroy(link);
close(pmu_fd);
close_prog: close_prog:
bpf_object__close(obj); bpf_object__close(obj);
} }
...@@ -3,18 +3,25 @@ ...@@ -3,18 +3,25 @@
void test_stacktrace_map_raw_tp(void) void test_stacktrace_map_raw_tp(void)
{ {
const char *prog_name = "tracepoint/sched/sched_switch";
int control_map_fd, stackid_hmap_fd, stackmap_fd; int control_map_fd, stackid_hmap_fd, stackmap_fd;
const char *file = "./test_stacktrace_map.o"; const char *file = "./test_stacktrace_map.o";
int efd, err, prog_fd;
__u32 key, val, duration = 0; __u32 key, val, duration = 0;
int err, prog_fd;
struct bpf_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
struct bpf_link *link = NULL;
err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd); err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd);
if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno)) if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno))
return; return;
efd = bpf_raw_tracepoint_open("sched_switch", prog_fd); prog = bpf_object__find_program_by_title(obj, prog_name);
if (CHECK(efd < 0, "raw_tp_open", "err %d errno %d\n", efd, errno)) if (CHECK(!prog, "find_prog", "prog '%s' not found\n", prog_name))
goto close_prog;
link = bpf_program__attach_raw_tracepoint(prog, "sched_switch");
if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n", PTR_ERR(link)))
goto close_prog; goto close_prog;
/* find map fds */ /* find map fds */
...@@ -55,5 +62,7 @@ void test_stacktrace_map_raw_tp(void) ...@@ -55,5 +62,7 @@ void test_stacktrace_map_raw_tp(void)
close_prog: close_prog:
error_cnt++; error_cnt++;
close_prog_noerr: close_prog_noerr:
if (!IS_ERR_OR_NULL(link))
bpf_link__destroy(link);
bpf_object__close(obj); bpf_object__close(obj);
} }
...@@ -58,26 +58,18 @@ struct frag_hdr { ...@@ -58,26 +58,18 @@ struct frag_hdr {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__u32 max_entries; __uint(max_entries, 8);
__u32 key_size; __uint(key_size, sizeof(__u32));
__u32 value_size; __uint(value_size, sizeof(__u32));
} jmp_table SEC(".maps") = { } jmp_table SEC(".maps");
.type = BPF_MAP_TYPE_PROG_ARRAY,
.max_entries = 8,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
struct bpf_flow_keys *value; __type(value, struct bpf_flow_keys);
} last_dissection SEC(".maps") = { } last_dissection SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
static __always_inline int export_flow_keys(struct bpf_flow_keys *keys, static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
int ret) int ret)
......
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include "bpf_helpers.h" #include "bpf_helpers.h"
struct bpf_map_def SEC("maps") cg_ids = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __uint(max_entries, 1);
.value_size = sizeof(__u64), __type(key, __u32);
.max_entries = 1, __type(value, __u64);
}; } cg_ids SEC(".maps");
struct bpf_map_def SEC("maps") pidmap = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __uint(max_entries, 1);
.value_size = sizeof(__u32), __type(key, __u32);
.max_entries = 1, __type(value, __u32);
}; } pidmap SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_nanosleep") SEC("tracepoint/syscalls/sys_enter_nanosleep")
int trace(void *ctx) int trace(void *ctx)
......
...@@ -11,20 +11,16 @@ ...@@ -11,20 +11,16 @@
#define NS_PER_SEC 1000000000 #define NS_PER_SEC 1000000000
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
struct bpf_cgroup_storage_key *key; __type(key, struct bpf_cgroup_storage_key);
struct percpu_net_cnt *value; __type(value, struct percpu_net_cnt);
} percpu_netcnt SEC(".maps") = { } percpu_netcnt SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
struct bpf_cgroup_storage_key *key; __type(key, struct bpf_cgroup_storage_key);
struct net_cnt *value; __type(value, struct net_cnt);
} netcnt SEC(".maps") = { } netcnt SEC(".maps");
.type = BPF_MAP_TYPE_CGROUP_STORAGE,
};
SEC("cgroup/skb") SEC("cgroup/skb")
int bpf_nextcnt(struct __sk_buff *skb) int bpf_nextcnt(struct __sk_buff *skb)
......
...@@ -58,14 +58,6 @@ typedef struct { ...@@ -58,14 +58,6 @@ typedef struct {
} Event; } Event;
struct bpf_elf_map {
__u32 type;
__u32 size_key;
__u32 size_value;
__u32 max_elem;
__u32 flags;
};
typedef int pid_t; typedef int pid_t;
typedef struct { typedef struct {
...@@ -118,47 +110,47 @@ static __always_inline bool get_frame_data(void *frame_ptr, PidData *pidData, ...@@ -118,47 +110,47 @@ static __always_inline bool get_frame_data(void *frame_ptr, PidData *pidData,
return true; return true;
} }
struct bpf_elf_map SEC("maps") pidmap = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.size_key = sizeof(int), __uint(max_entries, 1);
.size_value = sizeof(PidData), __type(key, int);
.max_elem = 1, __type(value, PidData);
}; } pidmap SEC(".maps");
struct bpf_elf_map SEC("maps") eventmap = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.size_key = sizeof(int), __uint(max_entries, 1);
.size_value = sizeof(Event), __type(key, int);
.max_elem = 1, __type(value, Event);
}; } eventmap SEC(".maps");
struct bpf_elf_map SEC("maps") symbolmap = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.size_key = sizeof(Symbol), __uint(max_entries, 1);
.size_value = sizeof(int), __type(key, Symbol);
.max_elem = 1, __type(value, int);
}; } symbolmap SEC(".maps");
struct bpf_elf_map SEC("maps") statsmap = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.size_key = sizeof(Stats), __uint(max_entries, 1);
.size_value = sizeof(int), __type(key, int);
.max_elem = 1, __type(value, Stats);
}; } statsmap SEC(".maps");
struct bpf_elf_map SEC("maps") perfmap = { struct {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
.size_key = sizeof(int), __uint(max_entries, 32);
.size_value = sizeof(int), __uint(key_size, sizeof(int));
.max_elem = 32, __uint(value_size, sizeof(int));
}; } perfmap SEC(".maps");
struct bpf_elf_map SEC("maps") stackmap = { struct {
.type = BPF_MAP_TYPE_STACK_TRACE, __uint(type, BPF_MAP_TYPE_STACK_TRACE);
.size_key = sizeof(int), __uint(max_entries, 1000);
.size_value = sizeof(long long) * 127, __uint(key_size, sizeof(int));
.max_elem = 1000, __uint(value_size, sizeof(long long) * 127);
}; } stackmap SEC(".maps");
static __always_inline int __on_event(struct pt_regs *ctx) static __always_inline int __on_event(struct pt_regs *ctx)
{ {
......
...@@ -13,14 +13,11 @@ struct socket_cookie { ...@@ -13,14 +13,11 @@ struct socket_cookie {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_SK_STORAGE);
__u32 map_flags; __uint(map_flags, BPF_F_NO_PREALLOC);
int *key; __type(key, int);
struct socket_cookie *value; __type(value, struct socket_cookie);
} socket_cookies SEC(".maps") = { } socket_cookies SEC(".maps");
.type = BPF_MAP_TYPE_SK_STORAGE,
.map_flags = BPF_F_NO_PREALLOC,
};
SEC("cgroup/connect6") SEC("cgroup/connect6")
int set_cookie(struct bpf_sock_addr *ctx) int set_cookie(struct bpf_sock_addr *ctx)
......
...@@ -4,33 +4,33 @@ ...@@ -4,33 +4,33 @@
int _version SEC("version") = 1; int _version SEC("version") = 1;
struct bpf_map_def SEC("maps") sock_map_rx = { struct {
.type = BPF_MAP_TYPE_SOCKMAP, __uint(type, BPF_MAP_TYPE_SOCKMAP);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map_rx SEC(".maps");
struct bpf_map_def SEC("maps") sock_map_tx = { struct {
.type = BPF_MAP_TYPE_SOCKMAP, __uint(type, BPF_MAP_TYPE_SOCKMAP);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map_tx SEC(".maps");
struct bpf_map_def SEC("maps") sock_map_msg = { struct {
.type = BPF_MAP_TYPE_SOCKMAP, __uint(type, BPF_MAP_TYPE_SOCKMAP);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map_msg SEC(".maps");
struct bpf_map_def SEC("maps") sock_map_break = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __type(key, int);
.max_entries = 20, __type(value, int);
}; } sock_map_break SEC(".maps");
SEC("sk_skb2") SEC("sk_skb2")
int bpf_prog2(struct __sk_buff *skb) int bpf_prog2(struct __sk_buff *skb)
......
...@@ -204,40 +204,40 @@ struct strobelight_bpf_sample { ...@@ -204,40 +204,40 @@ struct strobelight_bpf_sample {
char dummy_safeguard; char dummy_safeguard;
}; };
struct bpf_map_def SEC("maps") samples = { struct {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 32);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 32, __uint(value_size, sizeof(int));
}; } samples SEC(".maps");
struct bpf_map_def SEC("maps") stacks_0 = { struct {
.type = BPF_MAP_TYPE_STACK_TRACE, __uint(type, BPF_MAP_TYPE_STACK_TRACE);
.key_size = sizeof(uint32_t), __uint(max_entries, 16);
.value_size = sizeof(uint64_t) * PERF_MAX_STACK_DEPTH, __uint(key_size, sizeof(uint32_t));
.max_entries = 16, __uint(value_size, sizeof(uint64_t) * PERF_MAX_STACK_DEPTH);
}; } stacks_0 SEC(".maps");
struct bpf_map_def SEC("maps") stacks_1 = { struct {
.type = BPF_MAP_TYPE_STACK_TRACE, __uint(type, BPF_MAP_TYPE_STACK_TRACE);
.key_size = sizeof(uint32_t), __uint(max_entries, 16);
.value_size = sizeof(uint64_t) * PERF_MAX_STACK_DEPTH, __uint(key_size, sizeof(uint32_t));
.max_entries = 16, __uint(value_size, sizeof(uint64_t) * PERF_MAX_STACK_DEPTH);
}; } stacks_1 SEC(".maps");
struct bpf_map_def SEC("maps") sample_heap = { struct {
.type = BPF_MAP_TYPE_PERCPU_ARRAY, __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
.key_size = sizeof(uint32_t), __uint(max_entries, 1);
.value_size = sizeof(struct strobelight_bpf_sample), __type(key, uint32_t);
.max_entries = 1, __type(value, struct strobelight_bpf_sample);
}; } sample_heap SEC(".maps");
struct bpf_map_def SEC("maps") strobemeta_cfgs = { struct {
.type = BPF_MAP_TYPE_PERCPU_ARRAY, __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
.key_size = sizeof(pid_t), __uint(max_entries, STROBE_MAX_CFGS);
.value_size = sizeof(struct strobemeta_cfg), __type(key, pid_t);
.max_entries = STROBE_MAX_CFGS, __type(value, struct strobemeta_cfg);
}; } strobemeta_cfgs SEC(".maps");
/* Type for the dtv. */ /* Type for the dtv. */
/* https://github.com/lattera/glibc/blob/master/nptl/sysdeps/x86_64/tls.h#L34 */ /* https://github.com/lattera/glibc/blob/master/nptl/sysdeps/x86_64/tls.h#L34 */
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Facebook
#include <linux/ptrace.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 4);
__type(key, int);
__type(value, int);
} results_map SEC(".maps");
SEC("kprobe/sys_nanosleep")
int handle_sys_nanosleep_entry(struct pt_regs *ctx)
{
const int key = 0, value = 1;
bpf_map_update_elem(&results_map, &key, &value, 0);
return 0;
}
SEC("kretprobe/sys_nanosleep")
int handle_sys_getpid_return(struct pt_regs *ctx)
{
const int key = 1, value = 2;
bpf_map_update_elem(&results_map, &key, &value, 0);
return 0;
}
SEC("uprobe/trigger_func")
int handle_uprobe_entry(struct pt_regs *ctx)
{
const int key = 2, value = 3;
bpf_map_update_elem(&results_map, &key, &value, 0);
return 0;
}
SEC("uretprobe/trigger_func")
int handle_uprobe_return(struct pt_regs *ctx)
{
const int key = 3, value = 4;
bpf_map_update_elem(&results_map, &key, &value, 0);
return 0;
}
char _license[] SEC("license") = "GPL";
__u32 _version SEC("version") = 1;
...@@ -21,14 +21,11 @@ struct bpf_map_def SEC("maps") btf_map_legacy = { ...@@ -21,14 +21,11 @@ struct bpf_map_def SEC("maps") btf_map_legacy = {
BPF_ANNOTATE_KV_PAIR(btf_map_legacy, int, struct ipv_counts); BPF_ANNOTATE_KV_PAIR(btf_map_legacy, int, struct ipv_counts);
struct { struct {
int *key; __uint(type, BPF_MAP_TYPE_ARRAY);
struct ipv_counts *value; __uint(max_entries, 4);
unsigned int type; __type(key, int);
unsigned int max_entries; __type(value, struct ipv_counts);
} btf_map SEC(".maps") = { } btf_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 4,
};
struct dummy_tracepoint_args { struct dummy_tracepoint_args {
unsigned long long pad; unsigned long long pad;
......
...@@ -16,26 +16,18 @@ struct stack_trace_t { ...@@ -16,26 +16,18 @@ struct stack_trace_t {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__u32 max_entries; __uint(max_entries, 2);
__u32 key_size; __uint(key_size, sizeof(int));
__u32 value_size; __uint(value_size, sizeof(__u32));
} perfmap SEC(".maps") = { } perfmap SEC(".maps");
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.max_entries = 2,
.key_size = sizeof(int),
.value_size = sizeof(__u32),
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
struct stack_trace_t *value; __type(value, struct stack_trace_t);
} stackdata_map SEC(".maps") = { } stackdata_map SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = 1,
};
/* Allocate per-cpu space twice the needed. For the code below /* Allocate per-cpu space twice the needed. For the code below
* usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK); * usize = bpf_get_stack(ctx, raw_data, max_len, BPF_F_USER_STACK);
...@@ -56,14 +48,11 @@ struct { ...@@ -56,14 +48,11 @@ struct {
* This is an acceptable workaround since there is one entry here. * This is an acceptable workaround since there is one entry here.
*/ */
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u64 (*value)[2 * MAX_STACK_RAWTP]; __u64 (*value)[2 * MAX_STACK_RAWTP];
} rawdata_map SEC(".maps") = { } rawdata_map SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = 1,
};
SEC("tracepoint/raw_syscalls/sys_enter") SEC("tracepoint/raw_syscalls/sys_enter")
int bpf_prog1(void *ctx) int bpf_prog1(void *ctx)
......
...@@ -8,24 +8,18 @@ ...@@ -8,24 +8,18 @@
#include "bpf_helpers.h" #include "bpf_helpers.h"
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 11);
__u32 *key; __type(key, __u32);
__u64 *value; __type(value, __u64);
} result_number SEC(".maps") = { } result_number SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 11,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 5);
__u32 *key; __type(key, __u32);
const char (*value)[32]; const char (*value)[32];
} result_string SEC(".maps") = { } result_string SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 5,
};
struct foo { struct foo {
__u8 a; __u8 a;
...@@ -34,14 +28,11 @@ struct foo { ...@@ -34,14 +28,11 @@ struct foo {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 5);
__u32 *key; __type(key, __u32);
struct foo *value; __type(value, struct foo);
} result_struct SEC(".maps") = { } result_struct SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 5,
};
/* Relocation tests for __u64s. */ /* Relocation tests for __u64s. */
static __u64 num0; static __u64 num0;
......
...@@ -170,54 +170,39 @@ struct eth_hdr { ...@@ -170,54 +170,39 @@ struct eth_hdr {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, MAX_VIPS);
struct vip *key; __type(key, struct vip);
struct vip_meta *value; __type(value, struct vip_meta);
} vip_map SEC(".maps") = { } vip_map SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = MAX_VIPS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, CH_RINGS_SIZE);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} ch_rings SEC(".maps") = { } ch_rings SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = CH_RINGS_SIZE,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, MAX_REALS);
__u32 *key; __type(key, __u32);
struct real_definition *value; __type(value, struct real_definition);
} reals SEC(".maps") = { } reals SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = MAX_REALS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, MAX_VIPS);
__u32 *key; __type(key, __u32);
struct vip_stats *value; __type(value, struct vip_stats);
} stats SEC(".maps") = { } stats SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = MAX_VIPS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, CTL_MAP_SIZE);
__u32 *key; __type(key, __u32);
struct ctl_value *value; __type(value, struct ctl_value);
} ctl_array SEC(".maps") = { } ctl_array SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = CTL_MAP_SIZE,
};
static __always_inline __u32 get_packet_hash(struct packet_description *pckt, static __always_inline __u32 get_packet_hash(struct packet_description *pckt,
bool ipv6) bool ipv6)
......
...@@ -166,54 +166,39 @@ struct eth_hdr { ...@@ -166,54 +166,39 @@ struct eth_hdr {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, MAX_VIPS);
struct vip *key; __type(key, struct vip);
struct vip_meta *value; __type(value, struct vip_meta);
} vip_map SEC(".maps") = { } vip_map SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = MAX_VIPS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, CH_RINGS_SIZE);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} ch_rings SEC(".maps") = { } ch_rings SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = CH_RINGS_SIZE,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, MAX_REALS);
__u32 *key; __type(key, __u32);
struct real_definition *value; __type(value, struct real_definition);
} reals SEC(".maps") = { } reals SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = MAX_REALS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, MAX_VIPS);
__u32 *key; __type(key, __u32);
struct vip_stats *value; __type(value, struct vip_stats);
} stats SEC(".maps") = { } stats SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = MAX_VIPS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, CTL_MAP_SIZE);
__u32 *key; __type(key, __u32);
struct ctl_value *value; __type(value, struct ctl_value);
} ctl_array SEC(".maps") = { } ctl_array SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = CTL_MAP_SIZE,
};
static __u32 get_packet_hash(struct packet_description *pckt, static __u32 get_packet_hash(struct packet_description *pckt,
bool ipv6) bool ipv6)
......
...@@ -5,23 +5,23 @@ ...@@ -5,23 +5,23 @@
#include <linux/types.h> #include <linux/types.h>
#include "bpf_helpers.h" #include "bpf_helpers.h"
struct bpf_map_def SEC("maps") mim_array = { struct {
.type = BPF_MAP_TYPE_ARRAY_OF_MAPS, __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
.key_size = sizeof(int), __uint(max_entries, 1);
__uint(map_flags, 0);
__uint(key_size, sizeof(__u32));
/* must be sizeof(__u32) for map in map */ /* must be sizeof(__u32) for map in map */
.value_size = sizeof(__u32), __uint(value_size, sizeof(__u32));
.max_entries = 1, } mim_array SEC(".maps");
.map_flags = 0,
}; struct {
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
struct bpf_map_def SEC("maps") mim_hash = { __uint(max_entries, 1);
.type = BPF_MAP_TYPE_HASH_OF_MAPS, __uint(map_flags, 0);
.key_size = sizeof(int), __uint(key_size, sizeof(int));
/* must be sizeof(__u32) for map in map */ /* must be sizeof(__u32) for map in map */
.value_size = sizeof(__u32), __uint(value_size, sizeof(__u32));
.max_entries = 1, } mim_hash SEC(".maps");
.map_flags = 0,
};
SEC("xdp_mimtest") SEC("xdp_mimtest")
int xdp_mimtest0(struct xdp_md *ctx) int xdp_mimtest0(struct xdp_md *ctx)
......
...@@ -12,14 +12,11 @@ struct hmap_elem { ...@@ -12,14 +12,11 @@ struct hmap_elem {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
struct hmap_elem *value; __type(value, struct hmap_elem);
} hash_map SEC(".maps") = { } hash_map SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 1,
};
struct array_elem { struct array_elem {
struct bpf_spin_lock lock; struct bpf_spin_lock lock;
...@@ -27,14 +24,11 @@ struct array_elem { ...@@ -27,14 +24,11 @@ struct array_elem {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
int *key; __type(key, int);
struct array_elem *value; __type(value, struct array_elem);
} array_map SEC(".maps") = { } array_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
SEC("map_lock_demo") SEC("map_lock_demo")
int bpf_map_lock_test(struct __sk_buff *skb) int bpf_map_lock_test(struct __sk_buff *skb)
......
...@@ -13,12 +13,12 @@ ...@@ -13,12 +13,12 @@
int _version SEC("version") = 1; int _version SEC("version") = 1;
struct bpf_map_def SEC("maps") test_map_id = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __uint(max_entries, 1);
.value_size = sizeof(__u64), __type(key, __u32);
.max_entries = 1, __type(value, __u64);
}; } test_map_id SEC(".maps");
SEC("test_obj_id_dummy") SEC("test_obj_id_dummy")
int test_obj_id(struct __sk_buff *skb) int test_obj_id(struct __sk_buff *skb)
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/ptrace.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} perf_buf_map SEC(".maps");
SEC("kprobe/sys_nanosleep")
int handle_sys_nanosleep_entry(struct pt_regs *ctx)
{
int cpu = bpf_get_smp_processor_id();
bpf_perf_event_output(ctx, &perf_buf_map, BPF_F_CURRENT_CPU,
&cpu, sizeof(cpu));
return 0;
}
char _license[] SEC("license") = "GPL";
__u32 _version SEC("version") = 1;
...@@ -22,56 +22,39 @@ int _version SEC("version") = 1; ...@@ -22,56 +22,39 @@ int _version SEC("version") = 1;
#endif #endif
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__u32 max_entries; __uint(max_entries, 1);
__u32 key_size; __uint(key_size, sizeof(__u32));
__u32 value_size; __uint(value_size, sizeof(__u32));
} outer_map SEC(".maps") = { } outer_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
.max_entries = 1,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, NR_RESULTS);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} result_map SEC(".maps") = { } result_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = NR_RESULTS,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
int *value; __type(value, int);
} tmp_index_ovr_map SEC(".maps") = { } tmp_index_ovr_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} linum_map SEC(".maps") = { } linum_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
struct data_check *value; __type(value, struct data_check);
} data_check_map SEC(".maps") = { } data_check_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
#define GOTO_DONE(_result) ({ \ #define GOTO_DONE(_result) ({ \
result = (_result); \ result = (_result); \
......
...@@ -5,24 +5,18 @@ ...@@ -5,24 +5,18 @@
#include "bpf_helpers.h" #include "bpf_helpers.h"
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u64 *value; __type(value, __u64);
} info_map SEC(".maps") = { } info_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u64 *value; __type(value, __u64);
} status_map SEC(".maps") = { } status_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
SEC("send_signal_demo") SEC("send_signal_demo")
int bpf_send_signal_test(void *ctx) int bpf_send_signal_test(void *ctx)
......
...@@ -28,44 +28,32 @@ enum bpf_linum_array_idx { ...@@ -28,44 +28,32 @@ enum bpf_linum_array_idx {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, __NR_BPF_ADDR_ARRAY_IDX);
__u32 *key; __type(key, __u32);
struct sockaddr_in6 *value; __type(value, struct sockaddr_in6);
} addr_map SEC(".maps") = { } addr_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = __NR_BPF_ADDR_ARRAY_IDX,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, __NR_BPF_RESULT_ARRAY_IDX);
__u32 *key; __type(key, __u32);
struct bpf_sock *value; __type(value, struct bpf_sock);
} sock_result_map SEC(".maps") = { } sock_result_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = __NR_BPF_RESULT_ARRAY_IDX,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, __NR_BPF_RESULT_ARRAY_IDX);
__u32 *key; __type(key, __u32);
struct bpf_tcp_sock *value; __type(value, struct bpf_tcp_sock);
} tcp_sock_result_map SEC(".maps") = { } tcp_sock_result_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = __NR_BPF_RESULT_ARRAY_IDX,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, __NR_BPF_LINUM_ARRAY_IDX);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} linum_map SEC(".maps") = { } linum_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = __NR_BPF_LINUM_ARRAY_IDX,
};
struct bpf_spinlock_cnt { struct bpf_spinlock_cnt {
struct bpf_spin_lock lock; struct bpf_spin_lock lock;
...@@ -73,24 +61,18 @@ struct bpf_spinlock_cnt { ...@@ -73,24 +61,18 @@ struct bpf_spinlock_cnt {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_SK_STORAGE);
__u32 map_flags; __uint(map_flags, BPF_F_NO_PREALLOC);
int *key; __type(key, int);
struct bpf_spinlock_cnt *value; __type(value, struct bpf_spinlock_cnt);
} sk_pkt_out_cnt SEC(".maps") = { } sk_pkt_out_cnt SEC(".maps");
.type = BPF_MAP_TYPE_SK_STORAGE,
.map_flags = BPF_F_NO_PREALLOC,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_SK_STORAGE);
__u32 map_flags; __uint(map_flags, BPF_F_NO_PREALLOC);
int *key; __type(key, int);
struct bpf_spinlock_cnt *value; __type(value, struct bpf_spinlock_cnt);
} sk_pkt_out_cnt10 SEC(".maps") = { } sk_pkt_out_cnt10 SEC(".maps");
.type = BPF_MAP_TYPE_SK_STORAGE,
.map_flags = BPF_F_NO_PREALLOC,
};
static bool is_loopback6(__u32 *a6) static bool is_loopback6(__u32 *a6)
{ {
......
...@@ -11,14 +11,11 @@ struct hmap_elem { ...@@ -11,14 +11,11 @@ struct hmap_elem {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 1);
int *key; __type(key, int);
struct hmap_elem *value; __type(value, struct hmap_elem);
} hmap SEC(".maps") = { } hmap SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 1,
};
struct cls_elem { struct cls_elem {
struct bpf_spin_lock lock; struct bpf_spin_lock lock;
...@@ -26,12 +23,10 @@ struct cls_elem { ...@@ -26,12 +23,10 @@ struct cls_elem {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
struct bpf_cgroup_storage_key *key; __type(key, struct bpf_cgroup_storage_key);
struct cls_elem *value; __type(value, struct cls_elem);
} cls_map SEC(".maps") = { } cls_map SEC(".maps");
.type = BPF_MAP_TYPE_CGROUP_STORAGE,
};
struct bpf_vqueue { struct bpf_vqueue {
struct bpf_spin_lock lock; struct bpf_spin_lock lock;
...@@ -42,14 +37,11 @@ struct bpf_vqueue { ...@@ -42,14 +37,11 @@ struct bpf_vqueue {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
int *key; __type(key, int);
struct bpf_vqueue *value; __type(value, struct bpf_vqueue);
} vqueue SEC(".maps") = { } vqueue SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
#define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) #define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20)
......
...@@ -9,51 +9,36 @@ ...@@ -9,51 +9,36 @@
#endif #endif
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} control_map SEC(".maps") = { } control_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 16384);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} stackid_hmap SEC(".maps") = { } stackid_hmap SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 16384,
};
typedef struct bpf_stack_build_id stack_trace_t[PERF_MAX_STACK_DEPTH]; typedef struct bpf_stack_build_id stack_trace_t[PERF_MAX_STACK_DEPTH];
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_STACK_TRACE);
__u32 max_entries; __uint(max_entries, 128);
__u32 map_flags; __uint(map_flags, BPF_F_STACK_BUILD_ID);
__u32 key_size; __uint(key_size, sizeof(__u32));
__u32 value_size; __uint(value_size, sizeof(stack_trace_t));
} stackmap SEC(".maps") = { } stackmap SEC(".maps");
.type = BPF_MAP_TYPE_STACK_TRACE,
.max_entries = 128,
.map_flags = BPF_F_STACK_BUILD_ID,
.key_size = sizeof(__u32),
.value_size = sizeof(stack_trace_t),
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 128);
__u32 *key; __type(key, __u32);
/* there seems to be a bug in kernel not handling typedef properly */ /* there seems to be a bug in kernel not handling typedef properly */
struct bpf_stack_build_id (*value)[PERF_MAX_STACK_DEPTH]; struct bpf_stack_build_id (*value)[PERF_MAX_STACK_DEPTH];
} stack_amap SEC(".maps") = { } stack_amap SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 128,
};
/* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */ /* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */
struct random_urandom_args { struct random_urandom_args {
......
...@@ -9,48 +9,34 @@ ...@@ -9,48 +9,34 @@
#endif #endif
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 1);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} control_map SEC(".maps") = { } control_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 16384);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} stackid_hmap SEC(".maps") = { } stackid_hmap SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 16384,
};
typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH]; typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH];
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_STACK_TRACE);
__u32 max_entries; __uint(max_entries, 16384);
__u32 key_size; __uint(key_size, sizeof(__u32));
__u32 value_size; __uint(value_size, sizeof(stack_trace_t));
} stackmap SEC(".maps") = { } stackmap SEC(".maps");
.type = BPF_MAP_TYPE_STACK_TRACE,
.max_entries = 16384,
.key_size = sizeof(__u32),
.value_size = sizeof(stack_trace_t),
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 16384);
__u32 *key; __type(key, __u32);
__u64 (*value)[PERF_MAX_STACK_DEPTH]; __u64 (*value)[PERF_MAX_STACK_DEPTH];
} stack_amap SEC(".maps") = { } stack_amap SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 16384,
};
/* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */ /* taken from /sys/kernel/debug/tracing/events/sched/sched_switch/format */
struct sched_switch_args { struct sched_switch_args {
......
...@@ -149,14 +149,11 @@ struct tcp_estats_basic_event { ...@@ -149,14 +149,11 @@ struct tcp_estats_basic_event {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 1024);
__u32 *key; __type(key, __u32);
struct tcp_estats_basic_event *value; __type(value, struct tcp_estats_basic_event);
} ev_record_map SEC(".maps") = { } ev_record_map SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 1024,
};
struct dummy_tracepoint_args { struct dummy_tracepoint_args {
unsigned long long pad; unsigned long long pad;
......
...@@ -15,24 +15,18 @@ ...@@ -15,24 +15,18 @@
#include "test_tcpbpf.h" #include "test_tcpbpf.h"
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 4);
__u32 *key; __type(key, __u32);
struct tcpbpf_globals *value; __type(value, struct tcpbpf_globals);
} global_map SEC(".maps") = { } global_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 4,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 2);
__u32 *key; __type(key, __u32);
int *value; __type(value, int);
} sockopt_results SEC(".maps") = { } sockopt_results SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 2,
};
static inline void update_event_map(int event) static inline void update_event_map(int event)
{ {
......
...@@ -15,26 +15,18 @@ ...@@ -15,26 +15,18 @@
#include "test_tcpnotify.h" #include "test_tcpnotify.h"
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 4);
__u32 *key; __type(key, __u32);
struct tcpnotify_globals *value; __type(value, struct tcpnotify_globals);
} global_map SEC(".maps") = { } global_map SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 4,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__u32 max_entries; __uint(max_entries, 2);
__u32 key_size; __uint(key_size, sizeof(int));
__u32 value_size; __uint(value_size, sizeof(__u32));
} perf_event_map SEC(".maps") = { } perf_event_map SEC(".maps");
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.max_entries = 2,
.key_size = sizeof(int),
.value_size = sizeof(__u32),
};
int _version SEC("version") = 1; int _version SEC("version") = 1;
......
...@@ -23,24 +23,18 @@ ...@@ -23,24 +23,18 @@
int _version SEC("version") = 1; int _version SEC("version") = 1;
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, 256);
__u32 *key; __type(key, __u32);
__u64 *value; __type(value, __u64);
} rxcnt SEC(".maps") = { } rxcnt SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = 256,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, MAX_IPTNL_ENTRIES);
struct vip *key; __type(key, struct vip);
struct iptnl_info *value; __type(value, struct iptnl_info);
} vip2tnl SEC(".maps") = { } vip2tnl SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = MAX_IPTNL_ENTRIES,
};
static __always_inline void count_tx(__u32 protocol) static __always_inline void count_tx(__u32 protocol)
{ {
......
...@@ -18,19 +18,19 @@ ...@@ -18,19 +18,19 @@
int _version SEC("version") = 1; int _version SEC("version") = 1;
struct bpf_map_def SEC("maps") rxcnt = { struct {
.type = BPF_MAP_TYPE_PERCPU_ARRAY, __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
.key_size = sizeof(__u32), __uint(max_entries, 256);
.value_size = sizeof(__u64), __type(key, __u32);
.max_entries = 256, __type(value, __u64);
}; } rxcnt SEC(".maps");
struct bpf_map_def SEC("maps") vip2tnl = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(struct vip), __uint(max_entries, MAX_IPTNL_ENTRIES);
.value_size = sizeof(struct iptnl_info), __type(key, struct vip);
.max_entries = MAX_IPTNL_ENTRIES, __type(value, struct iptnl_info);
}; } vip2tnl SEC(".maps");
static __always_inline void count_tx(__u32 protocol) static __always_inline void count_tx(__u32 protocol)
{ {
......
...@@ -164,66 +164,47 @@ struct lb_stats { ...@@ -164,66 +164,47 @@ struct lb_stats {
}; };
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_HASH);
__u32 max_entries; __uint(max_entries, 512);
struct vip_definition *key; __type(key, struct vip_definition);
struct vip_meta *value; __type(value, struct vip_meta);
} vip_map SEC(".maps") = { } vip_map SEC(".maps");
.type = BPF_MAP_TYPE_HASH,
.max_entries = 512,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_LRU_HASH);
__u32 max_entries; __uint(max_entries, 300);
__u32 map_flags; __uint(map_flags, 1U << 1);
struct flow_key *key; __type(key, struct flow_key);
struct real_pos_lru *value; __type(value, struct real_pos_lru);
} lru_cache SEC(".maps") = { } lru_cache SEC(".maps");
.type = BPF_MAP_TYPE_LRU_HASH,
.max_entries = 300,
.map_flags = 1U << 1,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 12 * 655);
__u32 *key; __type(key, __u32);
__u32 *value; __type(value, __u32);
} ch_rings SEC(".maps") = { } ch_rings SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 12 * 655,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 40);
__u32 *key; __type(key, __u32);
struct real_definition *value; __type(value, struct real_definition);
} reals SEC(".maps") = { } reals SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 40,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__u32 max_entries; __uint(max_entries, 515);
__u32 *key; __type(key, __u32);
struct lb_stats *value; __type(value, struct lb_stats);
} stats SEC(".maps") = { } stats SEC(".maps");
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.max_entries = 515,
};
struct { struct {
__u32 type; __uint(type, BPF_MAP_TYPE_ARRAY);
__u32 max_entries; __uint(max_entries, 16);
__u32 *key; __type(key, __u32);
struct ctl_value *value; __type(value, struct ctl_value);
} ctl_array SEC(".maps") = { } ctl_array SEC(".maps");
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 16,
};
struct eth_hdr { struct eth_hdr {
unsigned char eth_dest[6]; unsigned char eth_dest[6];
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include "bpf_helpers.h" #include "bpf_helpers.h"
struct bpf_map_def SEC("maps") tx_port = { struct {
.type = BPF_MAP_TYPE_DEVMAP, __uint(type, BPF_MAP_TYPE_DEVMAP);
.key_size = sizeof(int), __uint(max_entries, 8);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 8, __uint(value_size, sizeof(int));
}; } tx_port SEC(".maps");
SEC("redirect_map_0") SEC("redirect_map_0")
int xdp_redirect_map_0(struct xdp_md *xdp) int xdp_redirect_map_0(struct xdp_md *xdp)
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
#include "xdping.h" #include "xdping.h"
struct bpf_map_def SEC("maps") ping_map = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(__u32), __uint(max_entries, 256);
.value_size = sizeof(struct pinginfo), __type(key, __u32);
.max_entries = 256, __type(value, struct pinginfo);
}; } ping_map SEC(".maps");
static __always_inline void swap_src_dst_mac(void *data) static __always_inline void swap_src_dst_mac(void *data)
{ {
......
...@@ -180,7 +180,7 @@ static struct bpf_align_test tests[] = { ...@@ -180,7 +180,7 @@ static struct bpf_align_test tests[] = {
}, },
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .prog_type = BPF_PROG_TYPE_SCHED_CLS,
.matches = { .matches = {
{7, "R0=pkt(id=0,off=8,r=8,imm=0)"}, {7, "R0_w=pkt(id=0,off=8,r=8,imm=0)"},
{7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"}, {7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
{8, "R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"}, {8, "R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
{9, "R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, {9, "R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
...@@ -315,7 +315,7 @@ static struct bpf_align_test tests[] = { ...@@ -315,7 +315,7 @@ static struct bpf_align_test tests[] = {
/* Calculated offset in R6 has unknown value, but known /* Calculated offset in R6 has unknown value, but known
* alignment of 4. * alignment of 4.
*/ */
{8, "R2=pkt(id=0,off=0,r=8,imm=0)"}, {8, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, {8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
/* Offset is added to packet pointer R5, resulting in /* Offset is added to packet pointer R5, resulting in
* known fixed offset, and variable offset from R6. * known fixed offset, and variable offset from R6.
...@@ -405,7 +405,7 @@ static struct bpf_align_test tests[] = { ...@@ -405,7 +405,7 @@ static struct bpf_align_test tests[] = {
/* Calculated offset in R6 has unknown value, but known /* Calculated offset in R6 has unknown value, but known
* alignment of 4. * alignment of 4.
*/ */
{8, "R2=pkt(id=0,off=0,r=8,imm=0)"}, {8, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, {8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
/* Adding 14 makes R6 be (4n+2) */ /* Adding 14 makes R6 be (4n+2) */
{9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, {9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
...@@ -473,12 +473,12 @@ static struct bpf_align_test tests[] = { ...@@ -473,12 +473,12 @@ static struct bpf_align_test tests[] = {
/* (4n) + 14 == (4n+2). We blow our bounds, because /* (4n) + 14 == (4n+2). We blow our bounds, because
* the add could overflow. * the add could overflow.
*/ */
{7, "R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"}, {7, "R5_w=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"},
/* Checked s>=0 */ /* Checked s>=0 */
{9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, {9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"},
/* packet pointer + nonnegative (4n+2) */ /* packet pointer + nonnegative (4n+2) */
{11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, {11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"},
{13, "R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, {13, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"},
/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. /* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
* We checked the bounds, but it might have been able * We checked the bounds, but it might have been able
* to overflow if the packet pointer started in the * to overflow if the packet pointer started in the
...@@ -486,7 +486,7 @@ static struct bpf_align_test tests[] = { ...@@ -486,7 +486,7 @@ static struct bpf_align_test tests[] = {
* So we did not get a 'range' on R6, and the access * So we did not get a 'range' on R6, and the access
* attempt will fail. * attempt will fail.
*/ */
{15, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, {15, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"},
} }
}, },
{ {
...@@ -521,7 +521,7 @@ static struct bpf_align_test tests[] = { ...@@ -521,7 +521,7 @@ static struct bpf_align_test tests[] = {
/* Calculated offset in R6 has unknown value, but known /* Calculated offset in R6 has unknown value, but known
* alignment of 4. * alignment of 4.
*/ */
{7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, {7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
{9, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, {9, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
/* Adding 14 makes R6 be (4n+2) */ /* Adding 14 makes R6 be (4n+2) */
{10, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, {10, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
...@@ -574,7 +574,7 @@ static struct bpf_align_test tests[] = { ...@@ -574,7 +574,7 @@ static struct bpf_align_test tests[] = {
/* Calculated offset in R6 has unknown value, but known /* Calculated offset in R6 has unknown value, but known
* alignment of 4. * alignment of 4.
*/ */
{7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, {7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
{10, "R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"}, {10, "R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"},
/* Adding 14 makes R6 be (4n+2) */ /* Adding 14 makes R6 be (4n+2) */
{11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"}, {11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},
......
...@@ -1418,7 +1418,7 @@ static void test_map_wronly(void) ...@@ -1418,7 +1418,7 @@ static void test_map_wronly(void)
assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM);
} }
static void prepare_reuseport_grp(int type, int map_fd, static void prepare_reuseport_grp(int type, int map_fd, size_t map_elem_size,
__s64 *fds64, __u64 *sk_cookies, __s64 *fds64, __u64 *sk_cookies,
unsigned int n) unsigned int n)
{ {
...@@ -1428,6 +1428,8 @@ static void prepare_reuseport_grp(int type, int map_fd, ...@@ -1428,6 +1428,8 @@ static void prepare_reuseport_grp(int type, int map_fd,
const int optval = 1; const int optval = 1;
unsigned int i; unsigned int i;
u64 sk_cookie; u64 sk_cookie;
void *value;
__s32 fd32;
__s64 fd64; __s64 fd64;
int err; int err;
...@@ -1449,8 +1451,14 @@ static void prepare_reuseport_grp(int type, int map_fd, ...@@ -1449,8 +1451,14 @@ static void prepare_reuseport_grp(int type, int map_fd,
"err:%d errno:%d\n", err, errno); "err:%d errno:%d\n", err, errno);
/* reuseport_array does not allow unbound sk */ /* reuseport_array does not allow unbound sk */
err = bpf_map_update_elem(map_fd, &index0, &fd64, if (map_elem_size == sizeof(__u64))
BPF_ANY); value = &fd64;
else {
assert(map_elem_size == sizeof(__u32));
fd32 = (__s32)fd64;
value = &fd32;
}
err = bpf_map_update_elem(map_fd, &index0, value, BPF_ANY);
CHECK(err != -1 || errno != EINVAL, CHECK(err != -1 || errno != EINVAL,
"reuseport array update unbound sk", "reuseport array update unbound sk",
"sock_type:%d err:%d errno:%d\n", "sock_type:%d err:%d errno:%d\n",
...@@ -1478,7 +1486,7 @@ static void prepare_reuseport_grp(int type, int map_fd, ...@@ -1478,7 +1486,7 @@ static void prepare_reuseport_grp(int type, int map_fd,
* reuseport_array does not allow * reuseport_array does not allow
* non-listening tcp sk. * non-listening tcp sk.
*/ */
err = bpf_map_update_elem(map_fd, &index0, &fd64, err = bpf_map_update_elem(map_fd, &index0, value,
BPF_ANY); BPF_ANY);
CHECK(err != -1 || errno != EINVAL, CHECK(err != -1 || errno != EINVAL,
"reuseport array update non-listening sk", "reuseport array update non-listening sk",
...@@ -1541,7 +1549,7 @@ static void test_reuseport_array(void) ...@@ -1541,7 +1549,7 @@ static void test_reuseport_array(void)
for (t = 0; t < ARRAY_SIZE(types); t++) { for (t = 0; t < ARRAY_SIZE(types); t++) {
type = types[t]; type = types[t];
prepare_reuseport_grp(type, map_fd, grpa_fds64, prepare_reuseport_grp(type, map_fd, sizeof(__u64), grpa_fds64,
grpa_cookies, ARRAY_SIZE(grpa_fds64)); grpa_cookies, ARRAY_SIZE(grpa_fds64));
/* Test BPF_* update flags */ /* Test BPF_* update flags */
...@@ -1649,7 +1657,8 @@ static void test_reuseport_array(void) ...@@ -1649,7 +1657,8 @@ static void test_reuseport_array(void)
sizeof(__u32), sizeof(__u32), array_size, 0); sizeof(__u32), sizeof(__u32), array_size, 0);
CHECK(map_fd == -1, "reuseport array create", CHECK(map_fd == -1, "reuseport array create",
"map_fd:%d, errno:%d\n", map_fd, errno); "map_fd:%d, errno:%d\n", map_fd, errno);
prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1); prepare_reuseport_grp(SOCK_STREAM, map_fd, sizeof(__u32), &fd64,
&sk_cookie, 1);
fd = fd64; fd = fd64;
err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST); err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
CHECK(err == -1, "reuseport array update 32 bit fd", CHECK(err == -1, "reuseport array update 32 bit fd",
......
...@@ -10,21 +10,21 @@ ...@@ -10,21 +10,21 @@
int _version SEC("version") = 1; int _version SEC("version") = 1;
struct bpf_map_def __attribute__ ((section("maps"), used)) map_in = { struct {
.type = MAP_TYPE, __uint(type, MAP_TYPE);
.key_size = 0, __uint(max_entries, 32);
.value_size = sizeof(__u32), __uint(map_flags, 0);
.max_entries = 32, __uint(key_size, 0);
.map_flags = 0, __uint(value_size, sizeof(__u32));
}; } map_in SEC(".maps");
struct bpf_map_def __attribute__ ((section("maps"), used)) map_out = { struct {
.type = MAP_TYPE, __uint(type, MAP_TYPE);
.key_size = 0, __uint(max_entries, 32);
.value_size = sizeof(__u32), __uint(map_flags, 0);
.max_entries = 32, __uint(key_size, 0);
.map_flags = 0, __uint(value_size, sizeof(__u32));
}; } map_out SEC(".maps");
SEC("test") SEC("test")
int _test(struct __sk_buff *skb) int _test(struct __sk_buff *skb)
......
...@@ -28,61 +28,61 @@ ...@@ -28,61 +28,61 @@
* are established and verdicts are decided. * are established and verdicts are decided.
*/ */
struct bpf_map_def SEC("maps") sock_map = { struct {
.type = TEST_MAP_TYPE, __uint(type, TEST_MAP_TYPE);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map SEC(".maps");
struct bpf_map_def SEC("maps") sock_map_txmsg = { struct {
.type = TEST_MAP_TYPE, __uint(type, TEST_MAP_TYPE);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map_txmsg SEC(".maps");
struct bpf_map_def SEC("maps") sock_map_redir = { struct {
.type = TEST_MAP_TYPE, __uint(type, TEST_MAP_TYPE);
.key_size = sizeof(int), __uint(max_entries, 20);
.value_size = sizeof(int), __uint(key_size, sizeof(int));
.max_entries = 20, __uint(value_size, sizeof(int));
}; } sock_map_redir SEC(".maps");
struct bpf_map_def SEC("maps") sock_apply_bytes = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 1);
.value_size = sizeof(int), __type(key, int);
.max_entries = 1 __type(value, int);
}; } sock_apply_bytes SEC(".maps");
struct bpf_map_def SEC("maps") sock_cork_bytes = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 1);
.value_size = sizeof(int), __type(key, int);
.max_entries = 1 __type(value, int);
}; } sock_cork_bytes SEC(".maps");
struct bpf_map_def SEC("maps") sock_bytes = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 6);
.value_size = sizeof(int), __type(key, int);
.max_entries = 6 __type(value, int);
}; } sock_bytes SEC(".maps");
struct bpf_map_def SEC("maps") sock_redir_flags = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 1);
.value_size = sizeof(int), __type(key, int);
.max_entries = 1 __type(value, int);
}; } sock_redir_flags SEC(".maps");
struct bpf_map_def SEC("maps") sock_skb_opts = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(max_entries, 1);
.value_size = sizeof(int), __type(key, int);
.max_entries = 1 __type(value, int);
}; } sock_skb_opts SEC(".maps");
SEC("sk_skb1") SEC("sk_skb1")
int bpf_prog1(struct __sk_buff *skb) int bpf_prog1(struct __sk_buff *skb)
......
...@@ -105,6 +105,7 @@ struct bpf_test { ...@@ -105,6 +105,7 @@ struct bpf_test {
__u64 data64[TEST_DATA_LEN / 8]; __u64 data64[TEST_DATA_LEN / 8];
}; };
} retvals[MAX_TEST_RUNS]; } retvals[MAX_TEST_RUNS];
enum bpf_attach_type expected_attach_type;
}; };
/* Note we want this to be 64 bit aligned so that the end of our array is /* Note we want this to be 64 bit aligned so that the end of our array is
...@@ -850,6 +851,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -850,6 +851,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
int fd_prog, expected_ret, alignment_prevented_execution; int fd_prog, expected_ret, alignment_prevented_execution;
int prog_len, prog_type = test->prog_type; int prog_len, prog_type = test->prog_type;
struct bpf_insn *prog = test->insns; struct bpf_insn *prog = test->insns;
struct bpf_load_program_attr attr;
int run_errs, run_successes; int run_errs, run_successes;
int map_fds[MAX_NR_MAPS]; int map_fds[MAX_NR_MAPS];
const char *expected_err; const char *expected_err;
...@@ -881,8 +883,17 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -881,8 +883,17 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
pflags |= BPF_F_STRICT_ALIGNMENT; pflags |= BPF_F_STRICT_ALIGNMENT;
if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) if (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)
pflags |= BPF_F_ANY_ALIGNMENT; pflags |= BPF_F_ANY_ALIGNMENT;
fd_prog = bpf_verify_program(prog_type, prog, prog_len, pflags,
"GPL", 0, bpf_vlog, sizeof(bpf_vlog), 4); memset(&attr, 0, sizeof(attr));
attr.prog_type = prog_type;
attr.expected_attach_type = test->expected_attach_type;
attr.insns = prog;
attr.insns_cnt = prog_len;
attr.license = "GPL";
attr.log_level = 4;
attr.prog_flags = pflags;
fd_prog = bpf_load_program_xattr(&attr, bpf_vlog, sizeof(bpf_vlog));
if (fd_prog < 0 && !bpf_probe_prog_type(prog_type, 0)) { if (fd_prog < 0 && !bpf_probe_prog_type(prog_type, 0)) {
printf("SKIP (unsupported program type %d)\n", prog_type); printf("SKIP (unsupported program type %d)\n", prog_type);
skips++; skips++;
...@@ -912,7 +923,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, ...@@ -912,7 +923,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
printf("FAIL\nUnexpected success to load!\n"); printf("FAIL\nUnexpected success to load!\n");
goto fail_log; goto fail_log;
} }
if (!strstr(bpf_vlog, expected_err)) { if (!expected_err || !strstr(bpf_vlog, expected_err)) {
printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n", printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n",
expected_err, bpf_vlog); expected_err, bpf_vlog);
goto fail_log; goto fail_log;
......
#define BPF_SOCK_ADDR(field, off, res, err) \
{ \
"wide store to bpf_sock_addr." #field "[" #off "]", \
.insns = { \
BPF_MOV64_IMM(BPF_REG_0, 1), \
BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, \
offsetof(struct bpf_sock_addr, field[off])), \
BPF_EXIT_INSN(), \
}, \
.result = res, \
.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR, \
.expected_attach_type = BPF_CGROUP_UDP6_SENDMSG, \
.errstr = err, \
}
/* user_ip6[0] is u64 aligned */
BPF_SOCK_ADDR(user_ip6, 0, ACCEPT,
NULL),
BPF_SOCK_ADDR(user_ip6, 1, REJECT,
"invalid bpf_context access off=12 size=8"),
BPF_SOCK_ADDR(user_ip6, 2, ACCEPT,
NULL),
BPF_SOCK_ADDR(user_ip6, 3, REJECT,
"invalid bpf_context access off=20 size=8"),
/* msg_src_ip6[0] is _not_ u64 aligned */
BPF_SOCK_ADDR(msg_src_ip6, 0, REJECT,
"invalid bpf_context access off=44 size=8"),
BPF_SOCK_ADDR(msg_src_ip6, 1, ACCEPT,
NULL),
BPF_SOCK_ADDR(msg_src_ip6, 2, REJECT,
"invalid bpf_context access off=52 size=8"),
BPF_SOCK_ADDR(msg_src_ip6, 3, REJECT,
"invalid bpf_context access off=56 size=8"),
#undef BPF_SOCK_ADDR
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment