diff --git a/examples/fentry/bpf_bpfeb.go b/examples/fentry/bpf_bpfeb.go index a01170979..c7b43805f 100644 --- a/examples/fentry/bpf_bpfeb.go +++ b/examples/fentry/bpf_bpfeb.go @@ -13,6 +13,14 @@ import ( "github.com/cilium/ebpf" ) +type bpfEvent struct { + Comm [16]uint8 + Sport uint16 + Dport uint16 + Saddr uint32 + Daddr uint32 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) diff --git a/examples/fentry/bpf_bpfeb.o b/examples/fentry/bpf_bpfeb.o index 85b165fde..03a3953b3 100644 Binary files a/examples/fentry/bpf_bpfeb.o and b/examples/fentry/bpf_bpfeb.o differ diff --git a/examples/fentry/bpf_bpfel.go b/examples/fentry/bpf_bpfel.go index 94c0a8d93..cd7e520d9 100644 --- a/examples/fentry/bpf_bpfel.go +++ b/examples/fentry/bpf_bpfel.go @@ -13,6 +13,14 @@ import ( "github.com/cilium/ebpf" ) +type bpfEvent struct { + Comm [16]uint8 + Sport uint16 + Dport uint16 + Saddr uint32 + Daddr uint32 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) diff --git a/examples/fentry/bpf_bpfel.o b/examples/fentry/bpf_bpfel.o index 2a3da277b..96a4a33f7 100644 Binary files a/examples/fentry/bpf_bpfel.o and b/examples/fentry/bpf_bpfel.o differ diff --git a/examples/fentry/fentry.c b/examples/fentry/fentry.c index 91323b330..1abe6d3cb 100644 --- a/examples/fentry/fentry.c +++ b/examples/fentry/fentry.c @@ -1,6 +1,8 @@ // +build ignore #include "common.h" + +#include "bpf_endian.h" #include "bpf_helpers.h" #include "bpf_tracing.h" @@ -38,8 +40,11 @@ struct { __uint(max_entries, 1 << 24); } events SEC(".maps"); -struct event_t { - char comm[16]; +// Force emitting struct event into the ELF. +const struct event *unused __attribute__((unused)); + +struct event { + u8 comm[16]; __u16 sport; __be16 dport; __be32 saddr; @@ -52,8 +57,8 @@ int BPF_PROG(tcp_connect, struct sock *sk) { return 0; } - struct event_t *tcp_info; - tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event_t), 0); + struct event *tcp_info; + tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0); if (!tcp_info) { return 0; } @@ -61,7 +66,7 @@ int BPF_PROG(tcp_connect, struct sock *sk) { tcp_info->saddr = sk->__sk_common.skc_rcv_saddr; tcp_info->daddr = sk->__sk_common.skc_daddr; tcp_info->dport = sk->__sk_common.skc_dport; - tcp_info->sport = sk->__sk_common.skc_num; + tcp_info->sport = bpf_htons(sk->__sk_common.skc_num); bpf_get_current_comm(&tcp_info->comm, TASK_COMM_LEN); diff --git a/examples/fentry/main.go b/examples/fentry/main.go index 35a667c8f..7ba1f3608 100644 --- a/examples/fentry/main.go +++ b/examples/fentry/main.go @@ -17,52 +17,22 @@ package main import ( + "bytes" "encoding/binary" "errors" - "fmt" "log" "net" "os" "os/signal" "syscall" - "github.com/cilium/ebpf/internal" - "github.com/cilium/ebpf/internal/unix" "github.com/cilium/ebpf/link" "github.com/cilium/ebpf/ringbuf" "github.com/cilium/ebpf/rlimit" ) // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile. -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf fentry.c -- -I../headers - -// Length of struct event_t sent from kernelspace. -var eventLength = 28 - -type Event struct { - Comm string - SPort uint16 - DPort uint16 - SAddr uint32 - DAddr uint32 -} - -// UnmarshalBinary unmarshals a ringbuf record into an Event. -func (e *Event) UnmarshalBinary(b []byte) error { - if len(b) != eventLength { - return fmt.Errorf("unexpected event length %d", len(b)) - } - - e.Comm = unix.ByteSliceToString(b[:16]) - - e.SPort = internal.NativeEndian.Uint16(b[16:18]) - e.DPort = binary.BigEndian.Uint16(b[18:20]) - - e.SAddr = binary.BigEndian.Uint32(b[20:24]) - e.DAddr = binary.BigEndian.Uint32(b[24:28]) - - return nil -} +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -type event bpf fentry.c -- -I../headers func main() { stopper := make(chan os.Signal, 1) @@ -110,7 +80,8 @@ func main() { "Port", ) - var event Event + // bpfEvent is generated by bpf2go. + var event bpfEvent for { record, err := rd.Read() if err != nil { @@ -122,17 +93,18 @@ func main() { continue } - // Parse the ringbuf event entry into an Event structure. - if err := event.UnmarshalBinary(record.RawSample); err != nil { - log.Fatal("unmarshaling event: %s", err) + // Parse the ringbuf event entry into a bpfEvent structure. + if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.BigEndian, &event); err != nil { + log.Printf("parsing ringbuf event: %s", err) + continue } log.Printf("%-16s %-15s %-6d -> %-15s %-6d", event.Comm, - intToIP(event.SAddr), - event.SPort, - intToIP(event.DAddr), - event.DPort, + intToIP(event.Saddr), + event.Sport, + intToIP(event.Daddr), + event.Dport, ) } } diff --git a/examples/go.mod b/examples/go.mod index dd598238a..b45167f8a 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -3,6 +3,6 @@ module github.com/cilium/ebpf/examples go 1.16 require ( - github.com/cilium/ebpf v0.7.1-0.20211126075831-9ead52e53c13 + github.com/cilium/ebpf v0.8.2-0.20220217141816-62da0a730ab7 golang.org/x/sys v0.0.0-20211001092434-39dca1131b70 ) diff --git a/examples/go.sum b/examples/go.sum index 39be9f4fa..11da27cf7 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,5 +1,5 @@ -github.com/cilium/ebpf v0.7.1-0.20211126075831-9ead52e53c13 h1:VrGaFU0ySWPDWlVQ7upRMX16MmU/hr6zw3Hia2HHmFM= -github.com/cilium/ebpf v0.7.1-0.20211126075831-9ead52e53c13/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= +github.com/cilium/ebpf v0.8.2-0.20220217141816-62da0a730ab7 h1:E9LSbo1EEbVIJ9w49myVxWmneomxCc2L7orPVXt0HeY= +github.com/cilium/ebpf v0.8.2-0.20220217141816-62da0a730ab7/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= diff --git a/examples/headers/LICENSE.BSD-2-Clause b/examples/headers/LICENSE.BSD-2-Clause new file mode 100644 index 000000000..da366e2ce --- /dev/null +++ b/examples/headers/LICENSE.BSD-2-Clause @@ -0,0 +1,32 @@ +Valid-License-Identifier: BSD-2-Clause +SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html +Usage-Guide: + To use the BSD 2-clause "Simplified" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-2-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/headers/bpf_endian.h b/examples/headers/bpf_endian.h new file mode 100644 index 000000000..ec9db4fec --- /dev/null +++ b/examples/headers/bpf_endian.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_ENDIAN__ +#define __BPF_ENDIAN__ + +/* + * Isolate byte #n and put it into byte #m, for __u##b type. + * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64: + * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx + * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000 + * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn + * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000 + */ +#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8)) + +#define ___bpf_swab16(x) ((__u16)( \ + ___bpf_mvb(x, 16, 0, 1) | \ + ___bpf_mvb(x, 16, 1, 0))) + +#define ___bpf_swab32(x) ((__u32)( \ + ___bpf_mvb(x, 32, 0, 3) | \ + ___bpf_mvb(x, 32, 1, 2) | \ + ___bpf_mvb(x, 32, 2, 1) | \ + ___bpf_mvb(x, 32, 3, 0))) + +#define ___bpf_swab64(x) ((__u64)( \ + ___bpf_mvb(x, 64, 0, 7) | \ + ___bpf_mvb(x, 64, 1, 6) | \ + ___bpf_mvb(x, 64, 2, 5) | \ + ___bpf_mvb(x, 64, 3, 4) | \ + ___bpf_mvb(x, 64, 4, 3) | \ + ___bpf_mvb(x, 64, 5, 2) | \ + ___bpf_mvb(x, 64, 6, 1) | \ + ___bpf_mvb(x, 64, 7, 0))) + +/* LLVM's BPF target selects the endianness of the CPU + * it compiles on, or the user specifies (bpfel/bpfeb), + * respectively. The used __BYTE_ORDER__ is defined by + * the compiler, we cannot rely on __BYTE_ORDER from + * libc headers, since it doesn't reflect the actual + * requested byte order. + * + * Note, LLVM's BPF target has different __builtin_bswapX() + * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE + * in bpfel and bpfeb case, which means below, that we map + * to cpu_to_be16(). We could use it unconditionally in BPF + * case, but better not rely on it, so that this header here + * can be used from application and BPF program side, which + * use different targets. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define __bpf_ntohs(x) __builtin_bswap16(x) +# define __bpf_htons(x) __builtin_bswap16(x) +# define __bpf_constant_ntohs(x) ___bpf_swab16(x) +# define __bpf_constant_htons(x) ___bpf_swab16(x) +# define __bpf_ntohl(x) __builtin_bswap32(x) +# define __bpf_htonl(x) __builtin_bswap32(x) +# define __bpf_constant_ntohl(x) ___bpf_swab32(x) +# define __bpf_constant_htonl(x) ___bpf_swab32(x) +# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) +# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) +# define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x) +# define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __bpf_ntohs(x) (x) +# define __bpf_htons(x) (x) +# define __bpf_constant_ntohs(x) (x) +# define __bpf_constant_htons(x) (x) +# define __bpf_ntohl(x) (x) +# define __bpf_htonl(x) (x) +# define __bpf_constant_ntohl(x) (x) +# define __bpf_constant_htonl(x) (x) +# define __bpf_be64_to_cpu(x) (x) +# define __bpf_cpu_to_be64(x) (x) +# define __bpf_constant_be64_to_cpu(x) (x) +# define __bpf_constant_cpu_to_be64(x) (x) +#else +# error "Fix your compiler's __BYTE_ORDER__?!" +#endif + +#define bpf_htons(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_htons(x) : __bpf_htons(x)) +#define bpf_ntohs(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_ntohs(x) : __bpf_ntohs(x)) +#define bpf_htonl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_htonl(x) : __bpf_htonl(x)) +#define bpf_ntohl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_ntohl(x) : __bpf_ntohl(x)) +#define bpf_cpu_to_be64(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) +#define bpf_be64_to_cpu(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) + +#endif /* __BPF_ENDIAN__ */ diff --git a/examples/headers/bpf_helper_defs.h b/examples/headers/bpf_helper_defs.h index f4f9b3b30..8a4edf613 100644 --- a/examples/headers/bpf_helper_defs.h +++ b/examples/headers/bpf_helper_defs.h @@ -27,6 +27,7 @@ struct tcp_sock; struct tcp_timewait_sock; struct tcp_request_sock; struct udp6_sock; +struct unix_sock; struct task_struct; struct __sk_buff; struct sk_msg_md; @@ -36,6 +37,7 @@ struct btf_ptr; struct inode; struct socket; struct file; +struct bpf_timer; /* * bpf_map_lookup_elem @@ -189,7 +191,7 @@ static __u32 (*bpf_get_prandom_u32)(void) = (void *) 7; * bpf_get_smp_processor_id * * Get the SMP (symmetric multiprocessing) processor id. Note that - * all programs run with preemption disabled, which means that the + * all programs run with migration disabled, which means that the * SMP processor id is stable during all the execution of the * program. * @@ -312,7 +314,7 @@ static long (*bpf_l4_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 fr * if the maximum number of tail calls has been reached for this * chain of programs. This limit is defined in the kernel by the * macro **MAX_TAIL_CALL_CNT** (not accessible to user space), - * which is currently set to 32. + * which is currently set to 33. * * Returns * 0 on success, or a negative error in case of failure. @@ -1277,8 +1279,12 @@ static long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32 * The lower two bits of *flags* are used as the return code if * the map lookup fails. This is so that the return value can be * one of the XDP program return codes up to **XDP_TX**, as chosen - * by the caller. Any higher bits in the *flags* argument must be - * unset. + * by the caller. The higher bits of *flags* can be set to + * BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below. + * + * With BPF_F_BROADCAST the packet will be broadcasted to all the + * interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress + * interface will be excluded when do broadcasting. * * See also **bpf_redirect**\ (), which only supports redirecting * to an ifindex, but doesn't require a map to do so. @@ -2090,7 +2096,7 @@ static void *(*bpf_get_local_storage)(void *map, __u64 flags) = (void *) 81; * bpf_sk_select_reuseport * * Select a **SO_REUSEPORT** socket from a - * **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*. + * **BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*. * It checks the selected socket is matching the incoming * request in the socket buffer. * @@ -3007,7 +3013,7 @@ static __u64 (*bpf_ktime_get_boot_ns)(void) = (void *) 125; * arguments. The *data* are a **u64** array and corresponding format string * values are stored in the array. For strings and pointers where pointees * are accessed, only the pointer values are stored in the *data* array. - * The *data_len* is the size of *data* in bytes. + * The *data_len* is the size of *data* in bytes - must be a multiple of 8. * * Formats **%s**, **%p{i,I}{4,6}** requires to read kernel memory. * Reading kernel memory may fail due to either invalid address or @@ -3868,7 +3874,8 @@ static long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callbac * Each format specifier in **fmt** corresponds to one u64 element * in the **data** array. For strings and pointers where pointees * are accessed, only the pointer values are stored in the *data* - * array. The *data_len* is the size of *data* in bytes. + * array. The *data_len* is the size of *data* in bytes - must be + * a multiple of 8. * * Formats **%s** and **%p{i,I}{4,6}** require to read kernel * memory. Reading kernel memory may fail due to either invalid @@ -3889,4 +3896,244 @@ static long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callbac */ static long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165; +/* + * bpf_sys_bpf + * + * Execute bpf syscall with given arguments. + * + * Returns + * A syscall result. + */ +static long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = (void *) 166; + +/* + * bpf_btf_find_by_name_kind + * + * Find BTF type with given name and kind in vmlinux BTF or in module's BTFs. + * + * Returns + * Returns btf_id and btf_obj_fd in lower and upper 32 bits. + */ +static long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = (void *) 167; + +/* + * bpf_sys_close + * + * Execute close syscall for given FD. + * + * Returns + * A syscall result. + */ +static long (*bpf_sys_close)(__u32 fd) = (void *) 168; + +/* + * bpf_timer_init + * + * Initialize the timer. + * First 4 bits of *flags* specify clockid. + * Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed. + * All other bits of *flags* are reserved. + * The verifier will reject the program if *timer* is not from + * the same *map*. + * + * Returns + * 0 on success. + * **-EBUSY** if *timer* is already initialized. + * **-EINVAL** if invalid *flags* are passed. + * **-EPERM** if *timer* is in a map that doesn't have any user references. + * The user space should either hold a file descriptor to a map with timers + * or pin such map in bpffs. When map is unpinned or file descriptor is + * closed all timers in the map will be cancelled and freed. + */ +static long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = (void *) 169; + +/* + * bpf_timer_set_callback + * + * Configure the timer to call *callback_fn* static function. + * + * Returns + * 0 on success. + * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. + * **-EPERM** if *timer* is in a map that doesn't have any user references. + * The user space should either hold a file descriptor to a map with timers + * or pin such map in bpffs. When map is unpinned or file descriptor is + * closed all timers in the map will be cancelled and freed. + */ +static long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = (void *) 170; + +/* + * bpf_timer_start + * + * Set timer expiration N nanoseconds from the current time. The + * configured callback will be invoked in soft irq context on some cpu + * and will not repeat unless another bpf_timer_start() is made. + * In such case the next invocation can migrate to a different cpu. + * Since struct bpf_timer is a field inside map element the map + * owns the timer. The bpf_timer_set_callback() will increment refcnt + * of BPF program to make sure that callback_fn code stays valid. + * When user space reference to a map reaches zero all timers + * in a map are cancelled and corresponding program's refcnts are + * decremented. This is done to make sure that Ctrl-C of a user + * process doesn't leave any timers running. If map is pinned in + * bpffs the callback_fn can re-arm itself indefinitely. + * bpf_map_update/delete_elem() helpers and user space sys_bpf commands + * cancel and free the timer in the given map element. + * The map can contain timers that invoke callback_fn-s from different + * programs. The same callback_fn can serve different timers from + * different maps if key/value layout matches across maps. + * Every bpf_timer_set_callback() can have different callback_fn. + * + * + * Returns + * 0 on success. + * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier + * or invalid *flags* are passed. + */ +static long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = (void *) 171; + +/* + * bpf_timer_cancel + * + * Cancel the timer and wait for callback_fn to finish if it was running. + * + * Returns + * 0 if the timer was not active. + * 1 if the timer was active. + * **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier. + * **-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its + * own timer which would have led to a deadlock otherwise. + */ +static long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172; + +/* + * bpf_get_func_ip + * + * Get address of the traced function (for tracing and kprobe programs). + * + * Returns + * Address of the traced function. + */ +static __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173; + +/* + * bpf_get_attach_cookie + * + * Get bpf_cookie value provided (optionally) during the program + * attachment. It might be different for each individual + * attachment, even if BPF program itself is the same. + * Expects BPF program context *ctx* as a first argument. + * + * Supported for the following program types: + * - kprobe/uprobe; + * - tracepoint; + * - perf_event. + * + * Returns + * Value specified by user at BPF link creation/attachment time + * or 0, if it was not specified. + */ +static __u64 (*bpf_get_attach_cookie)(void *ctx) = (void *) 174; + +/* + * bpf_task_pt_regs + * + * Get the struct pt_regs associated with **task**. + * + * Returns + * A pointer to struct pt_regs. + */ +static long (*bpf_task_pt_regs)(struct task_struct *task) = (void *) 175; + +/* + * bpf_get_branch_snapshot + * + * Get branch trace from hardware engines like Intel LBR. The + * hardware engine is stopped shortly after the helper is + * called. Therefore, the user need to filter branch entries + * based on the actual use case. To capture branch trace + * before the trigger point of the BPF program, the helper + * should be called at the beginning of the BPF program. + * + * The data is stored as struct perf_branch_entry into output + * buffer *entries*. *size* is the size of *entries* in bytes. + * *flags* is reserved for now and must be zero. + * + * + * Returns + * On success, number of bytes written to *buf*. On error, a + * negative value. + * + * **-EINVAL** if *flags* is not zero. + * + * **-ENOENT** if architecture does not support branch records. + */ +static long (*bpf_get_branch_snapshot)(void *entries, __u32 size, __u64 flags) = (void *) 176; + +/* + * bpf_trace_vprintk + * + * Behaves like **bpf_trace_printk**\ () helper, but takes an array of u64 + * to format and can handle more format args as a result. + * + * Arguments are to be used as in **bpf_seq_printf**\ () helper. + * + * Returns + * The number of bytes written to the buffer, or a negative error + * in case of failure. + */ +static long (*bpf_trace_vprintk)(const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 177; + +/* + * bpf_skc_to_unix_sock + * + * Dynamically cast a *sk* pointer to a *unix_sock* pointer. + * + * Returns + * *sk* if casting is valid, or **NULL** otherwise. + */ +static struct unix_sock *(*bpf_skc_to_unix_sock)(void *sk) = (void *) 178; + +/* + * bpf_kallsyms_lookup_name + * + * Get the address of a kernel symbol, returned in *res*. *res* is + * set to 0 if the symbol is not found. + * + * Returns + * On success, zero. On error, a negative value. + * + * **-EINVAL** if *flags* is not zero. + * + * **-EINVAL** if string *name* is not the same size as *name_sz*. + * + * **-ENOENT** if symbol is not found. + * + * **-EPERM** if caller does not have permission to obtain kernel address. + */ +static long (*bpf_kallsyms_lookup_name)(const char *name, int name_sz, int flags, __u64 *res) = (void *) 179; + +/* + * bpf_find_vma + * + * Find vma of *task* that contains *addr*, call *callback_fn* + * function with *task*, *vma*, and *callback_ctx*. + * The *callback_fn* should be a static function and + * the *callback_ctx* should be a pointer to the stack. + * The *flags* is used to control certain aspects of the helper. + * Currently, the *flags* must be 0. + * + * The expected callback signature is + * + * long (\*callback_fn)(struct task_struct \*task, struct vm_area_struct \*vma, void \*callback_ctx); + * + * + * Returns + * 0 on success. + * **-ENOENT** if *task->mm* is NULL, or no vma contains *addr*. + * **-EBUSY** if failed to try lock mmap_lock. + * **-EINVAL** for invalid **flags**. + */ +static long (*bpf_find_vma)(struct task_struct *task, __u64 addr, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 180; + diff --git a/examples/headers/bpf_helpers.h b/examples/headers/bpf_helpers.h index 9720dc0b4..963b1060d 100644 --- a/examples/headers/bpf_helpers.h +++ b/examples/headers/bpf_helpers.h @@ -14,14 +14,6 @@ #define __type(name, val) typeof(val) *name #define __array(name, val) typeof(val) *name[] -/* Helper macro to print out debug messages */ -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - /* * Helper macro to place programs, maps, license in * different sections in elf_bpf file. Section names @@ -158,4 +150,113 @@ enum libbpf_tristate { #define __kconfig __attribute__((section(".kconfig"))) #define __ksym __attribute__((section(".ksyms"))) +#ifndef ___bpf_concat +#define ___bpf_concat(a, b) a ## b +#endif +#ifndef ___bpf_apply +#define ___bpf_apply(fn, n) ___bpf_concat(fn, n) +#endif +#ifndef ___bpf_nth +#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N +#endif +#ifndef ___bpf_narg +#define ___bpf_narg(...) \ + ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#endif + +#define ___bpf_fill0(arr, p, x) do {} while (0) +#define ___bpf_fill1(arr, p, x) arr[p] = x +#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args) +#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args) +#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args) +#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args) +#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args) +#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args) +#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args) +#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args) +#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args) +#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args) +#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args) +#define ___bpf_fill(arr, args...) \ + ___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args) + +/* + * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values + * in a structure. + */ +#define BPF_SEQ_PRINTF(seq, fmt, args...) \ +({ \ + static const char ___fmt[] = fmt; \ + unsigned long long ___param[___bpf_narg(args)]; \ + \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ + ___bpf_fill(___param, args); \ + _Pragma("GCC diagnostic pop") \ + \ + bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \ + ___param, sizeof(___param)); \ +}) + +/* + * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of + * an array of u64. + */ +#define BPF_SNPRINTF(out, out_size, fmt, args...) \ +({ \ + static const char ___fmt[] = fmt; \ + unsigned long long ___param[___bpf_narg(args)]; \ + \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ + ___bpf_fill(___param, args); \ + _Pragma("GCC diagnostic pop") \ + \ + bpf_snprintf(out, out_size, ___fmt, \ + ___param, sizeof(___param)); \ +}) + +#ifdef BPF_NO_GLOBAL_DATA +#define BPF_PRINTK_FMT_MOD +#else +#define BPF_PRINTK_FMT_MOD static const +#endif + +#define __bpf_printk(fmt, ...) \ +({ \ + BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +/* + * __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments + * instead of an array of u64. + */ +#define __bpf_vprintk(fmt, args...) \ +({ \ + static const char ___fmt[] = fmt; \ + unsigned long long ___param[___bpf_narg(args)]; \ + \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ + ___bpf_fill(___param, args); \ + _Pragma("GCC diagnostic pop") \ + \ + bpf_trace_vprintk(___fmt, sizeof(___fmt), \ + ___param, sizeof(___param)); \ +}) + +/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args + * Otherwise use __bpf_vprintk + */ +#define ___bpf_pick_printk(...) \ + ___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ + __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ + __bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\ + __bpf_printk /*1*/, __bpf_printk /*0*/) + +/* Helper macro to print out debug messages */ +#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args) + #endif diff --git a/examples/headers/bpf_tracing.h b/examples/headers/bpf_tracing.h index 8c954ebc0..db05a5937 100644 --- a/examples/headers/bpf_tracing.h +++ b/examples/headers/bpf_tracing.h @@ -24,27 +24,42 @@ #elif defined(__TARGET_ARCH_sparc) #define bpf_target_sparc #define bpf_target_defined +#elif defined(__TARGET_ARCH_riscv) + #define bpf_target_riscv + #define bpf_target_defined #else - #undef bpf_target_defined -#endif /* Fall back to what the compiler says */ -#ifndef bpf_target_defined #if defined(__x86_64__) #define bpf_target_x86 + #define bpf_target_defined #elif defined(__s390__) #define bpf_target_s390 + #define bpf_target_defined #elif defined(__arm__) #define bpf_target_arm + #define bpf_target_defined #elif defined(__aarch64__) #define bpf_target_arm64 + #define bpf_target_defined #elif defined(__mips__) #define bpf_target_mips + #define bpf_target_defined #elif defined(__powerpc__) #define bpf_target_powerpc + #define bpf_target_defined #elif defined(__sparc__) #define bpf_target_sparc + #define bpf_target_defined +#elif defined(__riscv) && __riscv_xlen == 64 + #define bpf_target_riscv + #define bpf_target_defined +#endif /* no compiler target */ + #endif + +#ifndef __BPF_TARGET_MISSING +#define __BPF_TARGET_MISSING "GCC error \"Must specify a BPF target arch via __TARGET_ARCH_xxx\"" #endif #if defined(bpf_target_x86) @@ -279,6 +294,32 @@ struct pt_regs; #define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc) #endif +#elif defined(bpf_target_riscv) + +struct pt_regs; +#define PT_REGS_RV const volatile struct user_regs_struct +#define PT_REGS_PARM1(x) (((PT_REGS_RV *)(x))->a0) +#define PT_REGS_PARM2(x) (((PT_REGS_RV *)(x))->a1) +#define PT_REGS_PARM3(x) (((PT_REGS_RV *)(x))->a2) +#define PT_REGS_PARM4(x) (((PT_REGS_RV *)(x))->a3) +#define PT_REGS_PARM5(x) (((PT_REGS_RV *)(x))->a4) +#define PT_REGS_RET(x) (((PT_REGS_RV *)(x))->ra) +#define PT_REGS_FP(x) (((PT_REGS_RV *)(x))->s5) +#define PT_REGS_RC(x) (((PT_REGS_RV *)(x))->a5) +#define PT_REGS_SP(x) (((PT_REGS_RV *)(x))->sp) +#define PT_REGS_IP(x) (((PT_REGS_RV *)(x))->epc) + +#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a0) +#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a1) +#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a2) +#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a3) +#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a4) +#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), ra) +#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), fp) +#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a5) +#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), sp) +#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), epc) + #endif #if defined(bpf_target_powerpc) @@ -287,7 +328,7 @@ struct pt_regs; #elif defined(bpf_target_sparc) #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#else +#elif defined(bpf_target_defined) #define BPF_KPROBE_READ_RET_IP(ip, ctx) \ ({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ @@ -295,13 +336,48 @@ struct pt_regs; (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) #endif +#if !defined(bpf_target_defined) + +#define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) + +#define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) + +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) +#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) + +#endif /* !defined(bpf_target_defined) */ + +#ifndef ___bpf_concat #define ___bpf_concat(a, b) a ## b +#endif +#ifndef ___bpf_apply #define ___bpf_apply(fn, n) ___bpf_concat(fn, n) +#endif +#ifndef ___bpf_nth #define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N +#endif +#ifndef ___bpf_narg #define ___bpf_narg(...) \ ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#define ___bpf_empty(...) \ - ___bpf_nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0) +#endif #define ___bpf_ctx_cast0() ctx #define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0] @@ -413,56 +489,4 @@ typeof(name(0)) name(struct pt_regs *ctx) \ } \ static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) -#define ___bpf_fill0(arr, p, x) do {} while (0) -#define ___bpf_fill1(arr, p, x) arr[p] = x -#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args) -#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args) -#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args) -#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args) -#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args) -#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args) -#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args) -#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args) -#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args) -#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args) -#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args) -#define ___bpf_fill(arr, args...) \ - ___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args) - -/* - * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values - * in a structure. - */ -#define BPF_SEQ_PRINTF(seq, fmt, args...) \ -({ \ - static const char ___fmt[] = fmt; \ - unsigned long long ___param[___bpf_narg(args)]; \ - \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - ___bpf_fill(___param, args); \ - _Pragma("GCC diagnostic pop") \ - \ - bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \ - ___param, sizeof(___param)); \ -}) - -/* - * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of - * an array of u64. - */ -#define BPF_SNPRINTF(out, out_size, fmt, args...) \ -({ \ - static const char ___fmt[] = fmt; \ - unsigned long long ___param[___bpf_narg(args)]; \ - \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ - ___bpf_fill(___param, args); \ - _Pragma("GCC diagnostic pop") \ - \ - bpf_snprintf(out, out_size, ___fmt, \ - ___param, sizeof(___param)); \ -}) - #endif diff --git a/examples/headers/common.h b/examples/headers/common.h index 1a3d58a13..9ee76078b 100644 --- a/examples/headers/common.h +++ b/examples/headers/common.h @@ -1,7 +1,6 @@ // This is a compact version of `vmlinux.h` to be used in the examples using C code. -#ifndef __VMLINUX_H__ -#define __VMLINUX_H__ +#pragma once typedef unsigned char __u8; typedef short int __s16; @@ -24,42 +23,42 @@ typedef __u64 __be64; typedef __u32 __wsum; enum bpf_map_type { - BPF_MAP_TYPE_UNSPEC = 0, - BPF_MAP_TYPE_HASH = 1, - BPF_MAP_TYPE_ARRAY = 2, - BPF_MAP_TYPE_PROG_ARRAY = 3, - BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4, - BPF_MAP_TYPE_PERCPU_HASH = 5, - BPF_MAP_TYPE_PERCPU_ARRAY = 6, - BPF_MAP_TYPE_STACK_TRACE = 7, - BPF_MAP_TYPE_CGROUP_ARRAY = 8, - BPF_MAP_TYPE_LRU_HASH = 9, - BPF_MAP_TYPE_LRU_PERCPU_HASH = 10, - BPF_MAP_TYPE_LPM_TRIE = 11, - BPF_MAP_TYPE_ARRAY_OF_MAPS = 12, - BPF_MAP_TYPE_HASH_OF_MAPS = 13, - BPF_MAP_TYPE_DEVMAP = 14, - BPF_MAP_TYPE_SOCKMAP = 15, - BPF_MAP_TYPE_CPUMAP = 16, - BPF_MAP_TYPE_XSKMAP = 17, - BPF_MAP_TYPE_SOCKHASH = 18, - BPF_MAP_TYPE_CGROUP_STORAGE = 19, - BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20, + BPF_MAP_TYPE_UNSPEC = 0, + BPF_MAP_TYPE_HASH = 1, + BPF_MAP_TYPE_ARRAY = 2, + BPF_MAP_TYPE_PROG_ARRAY = 3, + BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4, + BPF_MAP_TYPE_PERCPU_HASH = 5, + BPF_MAP_TYPE_PERCPU_ARRAY = 6, + BPF_MAP_TYPE_STACK_TRACE = 7, + BPF_MAP_TYPE_CGROUP_ARRAY = 8, + BPF_MAP_TYPE_LRU_HASH = 9, + BPF_MAP_TYPE_LRU_PERCPU_HASH = 10, + BPF_MAP_TYPE_LPM_TRIE = 11, + BPF_MAP_TYPE_ARRAY_OF_MAPS = 12, + BPF_MAP_TYPE_HASH_OF_MAPS = 13, + BPF_MAP_TYPE_DEVMAP = 14, + BPF_MAP_TYPE_SOCKMAP = 15, + BPF_MAP_TYPE_CPUMAP = 16, + BPF_MAP_TYPE_XSKMAP = 17, + BPF_MAP_TYPE_SOCKHASH = 18, + BPF_MAP_TYPE_CGROUP_STORAGE = 19, + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21, - BPF_MAP_TYPE_QUEUE = 22, - BPF_MAP_TYPE_STACK = 23, - BPF_MAP_TYPE_SK_STORAGE = 24, - BPF_MAP_TYPE_DEVMAP_HASH = 25, - BPF_MAP_TYPE_STRUCT_OPS = 26, - BPF_MAP_TYPE_RINGBUF = 27, - BPF_MAP_TYPE_INODE_STORAGE = 28, + BPF_MAP_TYPE_QUEUE = 22, + BPF_MAP_TYPE_STACK = 23, + BPF_MAP_TYPE_SK_STORAGE = 24, + BPF_MAP_TYPE_DEVMAP_HASH = 25, + BPF_MAP_TYPE_STRUCT_OPS = 26, + BPF_MAP_TYPE_RINGBUF = 27, + BPF_MAP_TYPE_INODE_STORAGE = 28, }; enum { - BPF_ANY = 0, + BPF_ANY = 0, BPF_NOEXIST = 1, - BPF_EXIST = 2, - BPF_F_LOCK = 4, + BPF_EXIST = 2, + BPF_F_LOCK = 4, }; /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and @@ -68,19 +67,19 @@ enum { #define BPF_F_INDEX_MASK 0xffffffffULL #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK -#define PT_REGS_RC(x) ((x)->rax) +#if defined(__TARGET_ARCH_x86) struct pt_regs { -/* - * C ABI says these regs are callee-preserved. They aren't saved on kernel entry - * unless syscall needs a complete, fully filled "struct pt_regs". - */ + /* + * C ABI says these regs are callee-preserved. They aren't saved on kernel entry + * unless syscall needs a complete, fully filled "struct pt_regs". + */ unsigned long r15; unsigned long r14; unsigned long r13; unsigned long r12; unsigned long rbp; unsigned long rbx; -/* These regs are callee-clobbered. Always saved on kernel entry. */ + /* These regs are callee-clobbered. Always saved on kernel entry. */ unsigned long r11; unsigned long r10; unsigned long r9; @@ -90,18 +89,17 @@ struct pt_regs { unsigned long rdx; unsigned long rsi; unsigned long rdi; -/* - * On syscall entry, this is syscall#. On CPU exception, this is error code. - * On hw interrupt, it's IRQ number: - */ + /* + * On syscall entry, this is syscall#. On CPU exception, this is error code. + * On hw interrupt, it's IRQ number: + */ unsigned long orig_rax; -/* Return frame for iretq */ + /* Return frame for iretq */ unsigned long rip; unsigned long cs; unsigned long eflags; unsigned long rsp; unsigned long ss; -/* top of stack page */ + /* top of stack page */ }; - -#endif /* __VMLINUX_H__ */ +#endif /* __TARGET_ARCH_x86 */ diff --git a/examples/headers/update.sh b/examples/headers/update.sh index a36eb87f9..60f1cbd42 100755 --- a/examples/headers/update.sh +++ b/examples/headers/update.sh @@ -1,11 +1,13 @@ #!/usr/bin/env bash # Version of libbpf to fetch headers from -LIBBPF_VERSION=0.4.0 +LIBBPF_VERSION=0.6.1 # The headers we want prefix=libbpf-"$LIBBPF_VERSION" headers=( + "$prefix"/LICENSE.BSD-2-Clause + "$prefix"/src/bpf_endian.h "$prefix"/src/bpf_helper_defs.h "$prefix"/src/bpf_helpers.h "$prefix"/src/bpf_tracing.h diff --git a/examples/ringbuffer/bpf_bpfeb.go b/examples/ringbuffer/bpf_bpfeb.go index 0bb8e1a06..8a01deba0 100644 --- a/examples/ringbuffer/bpf_bpfeb.go +++ b/examples/ringbuffer/bpf_bpfeb.go @@ -13,6 +13,11 @@ import ( "github.com/cilium/ebpf" ) +type bpfEvent struct { + Pid uint32 + Comm [80]uint8 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) diff --git a/examples/ringbuffer/bpf_bpfeb.o b/examples/ringbuffer/bpf_bpfeb.o index 6fafd5f13..47074a2b5 100644 Binary files a/examples/ringbuffer/bpf_bpfeb.o and b/examples/ringbuffer/bpf_bpfeb.o differ diff --git a/examples/ringbuffer/bpf_bpfel.go b/examples/ringbuffer/bpf_bpfel.go index 2548b73ef..e62be884b 100644 --- a/examples/ringbuffer/bpf_bpfel.go +++ b/examples/ringbuffer/bpf_bpfel.go @@ -13,6 +13,11 @@ import ( "github.com/cilium/ebpf" ) +type bpfEvent struct { + Pid uint32 + Comm [80]uint8 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) diff --git a/examples/ringbuffer/bpf_bpfel.o b/examples/ringbuffer/bpf_bpfel.o index f8342d664..56689b9ad 100644 Binary files a/examples/ringbuffer/bpf_bpfel.o and b/examples/ringbuffer/bpf_bpfel.o differ diff --git a/examples/ringbuffer/main.go b/examples/ringbuffer/main.go index d332d8b33..f0c342b35 100644 --- a/examples/ringbuffer/main.go +++ b/examples/ringbuffer/main.go @@ -19,15 +19,7 @@ import ( ) // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile. -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf ringbuffer.c -- -I../headers - -// An Event represents a ringbuf event sent to userspace from the eBPF program -// running in the kernel. Note that this must match the C event_t structure, -// and that both C and Go structs must be aligned same way. -type Event struct { - PID uint32 - Comm [80]byte -} +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -type event bpf ringbuffer.c -- -I../headers func main() { // Name of the kernel function to trace. @@ -78,6 +70,8 @@ func main() { log.Println("Waiting for events..") + // bpfEvent is generated by bpf2go. + var event bpfEvent for { record, err := rd.Read() if err != nil { @@ -89,13 +83,12 @@ func main() { continue } - // Parse the ringbuf event entry into an Event structure. - var event Event + // Parse the ringbuf event entry into a bpfEvent structure. if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil { log.Printf("parsing ringbuf event: %s", err) continue } - log.Printf("pid: %d\tcomm: %s\n", event.PID, unix.ByteSliceToString(event.Comm[:])) + log.Printf("pid: %d\tcomm: %s\n", event.Pid, unix.ByteSliceToString(event.Comm[:])) } } diff --git a/examples/ringbuffer/ringbuffer.c b/examples/ringbuffer/ringbuffer.c index 226ebd0c0..e2d3ad240 100644 --- a/examples/ringbuffer/ringbuffer.c +++ b/examples/ringbuffer/ringbuffer.c @@ -1,13 +1,14 @@ // +build ignore #include "common.h" + #include "bpf_helpers.h" char __license[] SEC("license") = "Dual MIT/GPL"; -struct event_t { +struct event { u32 pid; - char comm[80]; + u8 comm[80]; }; struct { @@ -15,13 +16,16 @@ struct { __uint(max_entries, 1 << 24); } events SEC(".maps"); +// Force emitting struct event into the ELF. +const struct event *unused __attribute__((unused)); + SEC("kprobe/sys_execve") int kprobe_execve(struct pt_regs *ctx) { - u64 id = bpf_get_current_pid_tgid(); + u64 id = bpf_get_current_pid_tgid(); u32 tgid = id >> 32; - struct event_t *task_info; + struct event *task_info; - task_info = bpf_ringbuf_reserve(&events, sizeof(struct event_t), 0); + task_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0); if (!task_info) { return 0; } diff --git a/examples/uretprobe/bpf_bpfeb.o b/examples/uretprobe/bpf_bpfeb.o deleted file mode 100644 index 88281f71a..000000000 Binary files a/examples/uretprobe/bpf_bpfeb.o and /dev/null differ diff --git a/examples/uretprobe/bpf_bpfel.go b/examples/uretprobe/bpf_bpfel.go deleted file mode 100644 index bab91d8d8..000000000 --- a/examples/uretprobe/bpf_bpfel.go +++ /dev/null @@ -1,119 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 -// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64 - -package main - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -// loadBpf returns the embedded CollectionSpec for bpf. -func loadBpf() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_BpfBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load bpf: %w", err) - } - - return spec, err -} - -// loadBpfObjects loads bpf and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *bpfObjects -// *bpfPrograms -// *bpfMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := loadBpf() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// bpfSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfSpecs struct { - bpfProgramSpecs - bpfMapSpecs -} - -// bpfSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfProgramSpecs struct { - UretprobeBashReadline *ebpf.ProgramSpec `ebpf:"uretprobe_bash_readline"` -} - -// bpfMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfMapSpecs struct { - Events *ebpf.MapSpec `ebpf:"events"` -} - -// bpfObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfObjects struct { - bpfPrograms - bpfMaps -} - -func (o *bpfObjects) Close() error { - return _BpfClose( - &o.bpfPrograms, - &o.bpfMaps, - ) -} - -// bpfMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfMaps struct { - Events *ebpf.Map `ebpf:"events"` -} - -func (m *bpfMaps) Close() error { - return _BpfClose( - m.Events, - ) -} - -// bpfPrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfPrograms struct { - UretprobeBashReadline *ebpf.Program `ebpf:"uretprobe_bash_readline"` -} - -func (p *bpfPrograms) Close() error { - return _BpfClose( - p.UretprobeBashReadline, - ) -} - -func _BpfClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -//go:embed bpf_bpfel.o -var _BpfBytes []byte diff --git a/examples/uretprobe/bpf_bpfel.o b/examples/uretprobe/bpf_bpfel.o deleted file mode 100644 index 8e6b6abde..000000000 Binary files a/examples/uretprobe/bpf_bpfel.o and /dev/null differ diff --git a/examples/uretprobe/bpf_bpfeb.go b/examples/uretprobe/bpf_bpfel_x86.go similarity index 92% rename from examples/uretprobe/bpf_bpfeb.go rename to examples/uretprobe/bpf_bpfel_x86.go index 6f7b2d258..fed7fc124 100644 --- a/examples/uretprobe/bpf_bpfeb.go +++ b/examples/uretprobe/bpf_bpfel_x86.go @@ -1,6 +1,6 @@ // Code generated by bpf2go; DO NOT EDIT. -//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64 -// +build arm64be armbe mips mips64 mips64p32 ppc64 s390 s390x sparc sparc64 +//go:build 386 || amd64 +// +build 386 amd64 package main @@ -13,6 +13,11 @@ import ( "github.com/cilium/ebpf" ) +type bpfEvent struct { + Pid uint32 + Line [80]uint8 +} + // loadBpf returns the embedded CollectionSpec for bpf. func loadBpf() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_BpfBytes) @@ -115,5 +120,5 @@ func _BpfClose(closers ...io.Closer) error { } // Do not access this directly. -//go:embed bpf_bpfeb.o +//go:embed bpf_bpfel_x86.o var _BpfBytes []byte diff --git a/examples/uretprobe/bpf_bpfel_x86.o b/examples/uretprobe/bpf_bpfel_x86.o new file mode 100644 index 000000000..f40183487 Binary files /dev/null and b/examples/uretprobe/bpf_bpfel_x86.o differ diff --git a/examples/uretprobe/main.go b/examples/uretprobe/main.go index f444e54b2..3ae172443 100644 --- a/examples/uretprobe/main.go +++ b/examples/uretprobe/main.go @@ -22,15 +22,7 @@ import ( ) // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile. -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf uretprobe.c -- -I../headers - -// An Event represents a perf event sent to userspace from the eBPF program -// running in the kernel. Note that this must match the C event_t structure, -// and that both C and Go structs must be aligned same way. -type Event struct { - PID uint32 - Line [80]byte -} +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -target native -type event bpf uretprobe.c -- -I../headers const ( // The path to the ELF binary containing the function to trace. @@ -93,7 +85,8 @@ func main() { log.Printf("Listening for events..") - var event Event + // bpfEvent is generated by bpf2go. + var event bpfEvent for { record, err := rd.Read() if err != nil { @@ -109,7 +102,7 @@ func main() { continue } - // Parse the perf event entry into an Event structure. + // Parse the perf event entry into a bpfEvent structure. if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil { log.Printf("parsing perf event: %s", err) continue diff --git a/examples/uretprobe/uretprobe.c b/examples/uretprobe/uretprobe.c index 0110bba97..4e9db395c 100644 --- a/examples/uretprobe/uretprobe.c +++ b/examples/uretprobe/uretprobe.c @@ -1,25 +1,30 @@ // +build ignore #include "common.h" + #include "bpf_helpers.h" +#include "bpf_tracing.h" char __license[] SEC("license") = "Dual MIT/GPL"; -struct event_t { +struct event { u32 pid; - char str[80]; + u8 line[80]; }; struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); } events SEC(".maps"); +// Force emitting struct event into the ELF. +const struct event *unused __attribute__((unused)); + SEC("uretprobe/bash_readline") int uretprobe_bash_readline(struct pt_regs *ctx) { - struct event_t event; + struct event event; event.pid = bpf_get_current_pid_tgid(); - bpf_probe_read(&event.str, sizeof(event.str), (void *)PT_REGS_RC(ctx)); + bpf_probe_read(&event.line, sizeof(event.line), (void *)PT_REGS_RC(ctx)); bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));