hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9GZAQ CVE: NA
--------------------------------
ebpf for memory access by spe.
Signed-off-by: Ze Zuo zuoze1@huawei.com --- samples/bpf/spe/Makefile | 25 +++++++ samples/bpf/spe/Makefile.arch | 46 ++++++++++++ samples/bpf/spe/README.md | 0 samples/bpf/spe/spe-record.bpf.c | 41 +++++++++++ samples/bpf/spe/spe-record.h | 47 ++++++++++++ samples/bpf/spe/spe-record.user.c | 116 ++++++++++++++++++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 samples/bpf/spe/Makefile create mode 100644 samples/bpf/spe/Makefile.arch create mode 100644 samples/bpf/spe/README.md create mode 100644 samples/bpf/spe/spe-record.bpf.c create mode 100644 samples/bpf/spe/spe-record.h create mode 100644 samples/bpf/spe/spe-record.user.c
diff --git a/samples/bpf/spe/Makefile b/samples/bpf/spe/Makefile new file mode 100644 index 000000000000..946bfdba163e --- /dev/null +++ b/samples/bpf/spe/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 + +include Makefile.arch + +INSTALL ?= install +CLANG ?= clang +CC ?= gcc + +BPFTOOL ?= bpftool +KERNEL_DIR ?= ../../../ + +MKFLAGS = -I$(KERNEL_DIR)/tools/lib -I$(KERNEL_DIR)/tools/include/uapi/ \ + -D__BPF_TRACING__ -D__TARGET_ARCH_${SRCARCH} +LDLIBBPF = -L$(KERNEL_DIR)/tools/lib/bpf/ -l:libbpf.a + +all: + $(CLANG) -O2 -g -Wall -target bpf -I. ${MKFLAGS} -c spe-record.bpf.c -o spe-record.bpf.o + $(BPFTOOL) gen skeleton spe-record.bpf.o > spe-record.skel.h + $(CC) -O2 -g -Wall ${MKFLAGS} spe-record.user.c -o spe-record ${LDLIBBPF} -lelf -lz --static + +clean: + rm -f spe-record + rm -f vmlinux.h + rm -f *.o + rm -f *.skel.h diff --git a/samples/bpf/spe/Makefile.arch b/samples/bpf/spe/Makefile.arch new file mode 100644 index 000000000000..f6a50f06dfc4 --- /dev/null +++ b/samples/bpf/spe/Makefile.arch @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0 +HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ + -e s/sun4u/sparc/ -e s/sparc64/sparc/ \ + -e /arm64/!s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ + -e s/riscv.*/riscv/ -e s/loongarch.*/loongarch/) + +ifndef ARCH +ARCH := $(HOSTARCH) +endif + +SRCARCH := $(ARCH) + +# Additional ARCH settings for x86 +ifeq ($(ARCH),i386) + SRCARCH := x86 +endif +ifeq ($(ARCH),x86_64) + SRCARCH := x86 +endif + +# Additional ARCH settings for sparc +ifeq ($(ARCH),sparc32) + SRCARCH := sparc +endif +ifeq ($(ARCH),sparc64) + SRCARCH := sparc +endif + +# Additional ARCH settings for loongarch +ifeq ($(ARCH),loongarch32) + SRCARCH := loongarch +endif + +ifeq ($(ARCH),loongarch64) + SRCARCH := loongarch +endif + +LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) +ifeq ($(LP64), 1) + IS_64_BIT := 1 +else + IS_64_BIT := 0 +endif diff --git a/samples/bpf/spe/README.md b/samples/bpf/spe/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/samples/bpf/spe/spe-record.bpf.c b/samples/bpf/spe/spe-record.bpf.c new file mode 100644 index 000000000000..39d138a8e231 --- /dev/null +++ b/samples/bpf/spe/spe-record.bpf.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright (c) 2020 Andrii Nakryiko */ +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_core_read.h> +#include "spe-record.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + + +/* BPF ringbuf map */ +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024 /* 256 KB */); +} rb SEC(".maps"); + + +SEC("raw_tracepoint/spe_record") +int handle_exec(struct bpf_raw_tracepoint_args *ctx) +{ + + // TP_PROTO(struct mem_sampling_record *record) + struct mem_sampling_record *rd = (struct mem_sampling_record *)ctx->args[0]; + struct event *e; + + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return 0; + + if (bpf_get_current_comm(e->comm, sizeof(e->comm))) + e->comm[0] = 0; + + e->context_id = BPF_CORE_READ(rd, context_id); + e->virt_addr = BPF_CORE_READ(rd, virt_addr); + e->phys_addr = BPF_CORE_READ(rd, phys_addr); + e->latency = BPF_CORE_READ(rd, latency); + + bpf_ringbuf_submit(e, 0); + return 0; +} + diff --git a/samples/bpf/spe/spe-record.h b/samples/bpf/spe/spe-record.h new file mode 100644 index 000000000000..e9ec71bbb3a7 --- /dev/null +++ b/samples/bpf/spe/spe-record.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +/* Copyright (c) 2020 Andrii Nakryiko */ +#ifndef __SPE_RECORD_H +#define __SPE_RECORD_H + +enum mem_sampling_sample_type { + MEM_SAMPLING_L1D_ACCESS = 1 << 0, + MEM_SAMPLING_L1D_MISS = 1 << 1, + MEM_SAMPLING_LLC_ACCESS = 1 << 2, + MEM_SAMPLING_LLC_MISS = 1 << 3, + MEM_SAMPLING_TLB_ACCESS = 1 << 4, + MEM_SAMPLING_TLB_MISS = 1 << 5, + MEM_SAMPLING_BRANCH_MISS = 1 << 6, + MEM_SAMPLING_REMOTE_ACCESS = 1 << 7, +}; + +struct mem_sampling_record { + enum mem_sampling_sample_type type; + int err; + unsigned int op; + unsigned int latency; + unsigned long long from_ip; + unsigned long long to_ip; + unsigned long long timestamp; + unsigned long long virt_addr; + unsigned long long phys_addr; + unsigned long long context_id; + unsigned char source; +}; + +/* definition of a sample sent to user-space from BPF program */ +struct event { + enum mem_sampling_sample_type type; + int err; + unsigned int op; + unsigned int latency; + unsigned long long from_ip; + unsigned long long to_ip; + unsigned long long timestamp; + unsigned long long virt_addr; + unsigned long long phys_addr; + unsigned long long context_id; + unsigned char source; + char comm[16]; +}; + +#endif /* __SPE_RECORD_H */ diff --git a/samples/bpf/spe/spe-record.user.c b/samples/bpf/spe/spe-record.user.c new file mode 100644 index 000000000000..f81a59d65e2f --- /dev/null +++ b/samples/bpf/spe/spe-record.user.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +// Copyright (c) 2020 Andrii Nakryiko +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <time.h> +#include <sys/resource.h> +#include <bpf/libbpf.h> +#include "spe-record.h" +#include "spe-record.skel.h" + +int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +{ + /* Ignore debug-level libbpf logs */ + if (level > LIBBPF_INFO) + return 0; + return vfprintf(stderr, format, args); +} + +void bump_memlock_rlimit(void) +{ + struct rlimit rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { + fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); + exit(1); + } +} + +static bool exiting; + +static void sig_handler(int sig) +{ + exiting = true; +} + +int handle_event(void *ctx, void *data, size_t data_sz) +{ + const struct event *e = data; + struct tm *tm; + char ts[32]; + time_t t; + + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + + printf("%-20s %-8s %-10lld %-10d 0x%016llx 0x%016llx\n", e->comm, ts, e->context_id, + e->latency, e->virt_addr, e->phys_addr); + + return 0; +} + +int main(int argc, char **argv) +{ + struct ring_buffer *rb = NULL; + struct spe_record_bpf *skel; + int err; + + /* Set up libbpf logging callback */ + libbpf_set_print(libbpf_print_fn); + + /* Bump RLIMIT_MEMLOCK to create BPF maps */ + bump_memlock_rlimit(); + + /* Clean handling of Ctrl-C */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + /* Load and verify BPF application */ + skel = spe_record_bpf__open_and_load(); + if (!skel) { + fprintf(stderr, "Failed to open and load BPF skeleton\n"); + return 1; + } + + /* Attach tracepoint */ + err = spe_record_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + /* Set up ring buffer polling */ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto cleanup; + } + + /* Process events */ + printf("%-20s %-8s %-10s %-10s %-18s %-18s\n", + "COMM", "TIME", "PID", "LATENCY", "LADDR", "PADDR"); + while (!exiting) { + err = ring_buffer__poll(rb, 100 /* timeout, ms */); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling ring buffer: %d\n", err); + break; + } + } + +cleanup: + ring_buffer__free(rb); + spe_record_bpf__destroy(skel); + + return err < 0 ? -err : 0; +}