diff --git a/tools/ebpf/Makefile b/tools/ebpf/Makefile new file mode 100644 index 000000000..84783dee5 --- /dev/null +++ b/tools/ebpf/Makefile @@ -0,0 +1,24 @@ +.PHONY: all +all: et + +.PHONY: clean +clean: + rm -rf et *.o *.skel.h + +vmlinux.h: + bpftool btf dump file /sys/kernel/btf/vmlinux format c > $@ + +# Build BPF code, strip useless info +%.bpf.o: %.bpf.c vmlinux.h + clang -g -O2 -target bpf -c $(filter %.c,$^) -o $@ + llvm-strip -g $@ + +# Generate BPF skeletons +%.skel.h: %.bpf.o + bpftool gen skeleton $< > $@ + +# Get a list of all the .skel.h files +SKEL_FILES := $(patsubst %.bpf.c,%.skel.h,$(wildcard *.bpf.c)) + +et: et.c $(SKEL_FILES) + gcc -Wall -o $@ $(filter %.c,$^) -include $(SKEL_FILES) -l:libbpf.a -lelf -lz diff --git a/tools/ebpf/README.md b/tools/ebpf/README.md new file mode 100644 index 000000000..033dcc5e7 --- /dev/null +++ b/tools/ebpf/README.md @@ -0,0 +1,25 @@ +# eBPF tools + +This directory contains tools for eBPF. + +## Build + +Dependencies: libbpf, bpftool, clang, llvm, gcc. + +```bash +make +``` + +## Run + +in one shell: + +```bash +sudo ./et --print --fentry +``` + +then in another: + +```bash +sudo cat /sys/kernel/debug/tracing/trace_pipe +``` diff --git a/tools/ebpf/et.c b/tools/ebpf/et.c new file mode 100644 index 000000000..232261d15 --- /dev/null +++ b/tools/ebpf/et.c @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + * Copyright (c) 2023 Intel Corporation + */ +#include +#include +#include +#include +#include +#include +#include + +enum et_args_cmd { + ET_ARG_UNKNOWN = 0, + ET_ARG_PRINT_LIBBPF = 0x100, /* start from end of ascii */ + ET_ARG_FENTRY, + ET_ARG_HELP, +}; + +struct et_ctx { + bool not_yet; +}; + +static struct et_ctx g_ctx = {0}; +static volatile bool stop = false; + +static int libbpf_print_fn(enum libbpf_print_level level, const char* format, + va_list args) { + return vfprintf(stderr, format, args); +} + +static void et_sig_handler(int signo) { + printf("%s, signal %d\n", __func__, signo); + + switch (signo) { + case SIGINT: /* Interrupt from keyboard */ + stop = true; + break; + } + + return; +} + +static inline int et_fentry_loop() { + struct fentry_bpf* skel; + int ret = 0; + + skel = fentry_bpf__open_and_load(); + if (!skel) { + printf("failed to open BPF skeleton\n"); + return -1; + } + + ret = fentry_bpf__attach(skel); + if (ret) { + printf("failed to attach BPF skeleton\n"); + goto cleanup; + } + + printf("fentry_bpf__attach() succeeded\n"); + + while (!stop) { + fprintf(stderr, "."); + sleep(1); + } + +cleanup: + fentry_bpf__destroy(skel); + return ret; +} + +static struct option et_args_options[] = {{"print", no_argument, 0, ET_ARG_PRINT_LIBBPF}, + {"fentry", no_argument, 0, ET_ARG_FENTRY}, + {"help", no_argument, 0, ET_ARG_HELP}, + {0, 0, 0, 0}}; + +static void et_print_help() { + printf("\n"); + printf("##### Usage: #####\n\n"); + printf(" Params:\n"); + printf(" --help : print this help\n"); + printf(" --print : print libbpf output\n"); + printf(" --fentry : attach to fentry\n"); + printf("\n"); +} + +static int et_parse_args(struct et_ctx* ctx, int argc, char** argv) { + int cmd = -1, opt_idx = 0; + + while (1) { + cmd = getopt_long_only(argc, argv, "hv", et_args_options, &opt_idx); + if (cmd == -1) break; + + switch (cmd) { + case ET_ARG_FENTRY: + et_fentry_loop(); + break; + case ET_ARG_PRINT_LIBBPF: + libbpf_set_print(libbpf_print_fn); + break; + case ET_ARG_HELP: + default: + et_print_help(); + return -1; + } + }; + + return 0; +} + +int main(int argc, char** argv) { + et_parse_args(&g_ctx, argc, argv); + signal(SIGINT, et_sig_handler); + + return 0; +} \ No newline at end of file diff --git a/tools/ebpf/fentry.bpf.c b/tools/ebpf/fentry.bpf.c new file mode 100644 index 000000000..b56e17fb0 --- /dev/null +++ b/tools/ebpf/fentry.bpf.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + * Copyright (c) 2023 Intel Corporation + */ +//clang-format off +#include "vmlinux.h" +//clang-format off +#include +#include + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +SEC("fentry/udp_send_skb") +int BPF_PROG(udp_send_skb, struct sk_buff* skb, struct flowi4* fl4, + struct inet_cork* cork) { + pid_t pid; + + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("fentry: pid = %d, gso size = %u\n", pid, cork->gso_size); + return 0; +} + +SEC("fexit/udp_send_skb") +int BPF_PROG(udp_send_skb_exit, struct sk_buff* skb, struct flowi4* fl4, + struct inet_cork* cork, long ret) { + pid_t pid; + + pid = bpf_get_current_pid_tgid() >> 32; + bpf_printk("fexit: pid = %d, gso size = %u, ret = %ld\n", pid, cork->gso_size, ret); + return 0; +} \ No newline at end of file