Skip to content

Commit

Permalink
tools: add ebpf_tools (#548)
Browse files Browse the repository at this point in the history
The first tool is for tracing udp_send_skb calls.

---------

Signed-off-by: Ric Li <[email protected]>
  • Loading branch information
ricmli authored Oct 27, 2023
1 parent 824fc57 commit 25a78da
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 0 deletions.
27 changes: 27 additions & 0 deletions tools/ebpf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2023 Intel Corporation

.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
19 changes: 19 additions & 0 deletions tools/ebpf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# eBPF tools

This directory contains tools for eBPF.

## Build

Dependencies: libbpf, bpftool, clang, llvm, gcc, libelf, zlib.

```bash
make
```

## Run

fentry: a simple program to trace udp_send_skb calls, requires kernel > 5.5.

```bash
sudo ./et --prog fentry [--print]
```
169 changes: 169 additions & 0 deletions tools/ebpf/et.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2023 Intel Corporation
*/

#include "et.h"

#include <bpf/libbpf.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

enum et_args_cmd {
ET_ARG_UNKNOWN = 0,
ET_ARG_PRINT_LIBBPF = 0x100, /* start from end of ascii */
ET_ARG_PROG,
ET_ARG_HELP,
};

enum et_prog_type {
ET_PROG_UNKNOWN = 0,
ET_PROG_FENTRY,
ET_PROG_KPROBE,
ET_PROG_TRACEPOINT,
ET_PROG_XDP,
};

static const char* prog_type_str[] = {
[ET_PROG_FENTRY] = "fentry",
[ET_PROG_KPROBE] = "kprobe",
[ET_PROG_TRACEPOINT] = "tracepoint",
[ET_PROG_XDP] = "xdp",
};

struct et_ctx {
enum et_prog_type prog_type;
};

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 int udp_send_handler(void* ctx, void* data, size_t data_sz) {
const struct udp_send_event* e = data;

printf("%s: pid %d, gso_size %u, bytes %u, duration_ns %llu\n", __func__, e->pid,
e->gso_size, e->udp_send_bytes, e->duration_ns);
return 0;
}

static inline int et_fentry_loop() {
struct ring_buffer* rb = NULL;
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");

rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), udp_send_handler, NULL, NULL);
if (!rb) {
ret = -1;
fprintf(stderr, "failed to create ring buffer\n");
goto cleanup;
}

while (!stop) {
ret = ring_buffer__poll(rb, 100);
if (ret == -EINTR) {
ret = 0;
break;
}
if (ret < 0) {
printf("error polling perf buffer: %d\n", ret);
break;
}
}

cleanup:
ring_buffer__free(rb);
fentry_bpf__destroy(skel);
return ret;
}

static struct option et_args_options[] = {{"print", no_argument, 0, ET_ARG_PRINT_LIBBPF},
{"prog", required_argument, 0, ET_ARG_PROG},
{"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(" --prog <type> : attach to prog <type>\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_PROG:
if (strcmp(optarg, "fentry") == 0) {
ctx->prog_type = ET_PROG_FENTRY;
}
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) {
struct et_ctx ctx = {0};
et_parse_args(&ctx, argc, argv);
signal(SIGINT, et_sig_handler);

printf("prog type is %s\n", prog_type_str[ctx.prog_type]);
switch (ctx.prog_type) {
case ET_PROG_FENTRY:
et_fentry_loop();
break;

default:
break;
}

return 0;
}
17 changes: 17 additions & 0 deletions tools/ebpf/et.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2023 Intel Corporation
*/

#ifndef __ET_H
#define __ET_H

struct udp_send_event {
int pid;
int udp_send_cnt;
unsigned int gso_size;
unsigned long long duration_ns;
unsigned int udp_send_bytes;
int ret;
};

#endif /* __ET_H */
64 changes: 64 additions & 0 deletions tools/ebpf/fentry.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* 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 <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#include "et.h"

char LICENSE[] SEC("license") = "Dual BSD/GPL";

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, u64);
__type(value, u64);
} start_time SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");

SEC("fentry/udp_send_skb")
int BPF_PROG(udp_send_skb, struct sk_buff* skb, struct flowi4* fl4,
struct inet_cork* cork) {
u64 ts;
u64 skb_addr = (u64)skb;

ts = bpf_ktime_get_ns();
bpf_map_update_elem(&start_time, &skb_addr, &ts, BPF_ANY);

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) {
struct udp_send_event* e;
pid_t pid;
u64 *start_ts, duration_ns = 0;
u64 skb_addr = (u64)skb;

pid = bpf_get_current_pid_tgid() >> 32;
start_ts = bpf_map_lookup_elem(&start_time, &skb_addr);
if (start_ts) duration_ns = bpf_ktime_get_ns() - *start_ts;
bpf_map_delete_elem(&start_time, &skb_addr);

e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (!e) return 0;

e->pid = pid;
e->gso_size = cork->gso_size;
e->duration_ns = duration_ns;
e->udp_send_bytes = skb->len;
e->ret = ret;

bpf_ringbuf_submit(e, 0);

return 0;
}

0 comments on commit 25a78da

Please sign in to comment.