Skip to content

Commit

Permalink
Basic ringbuf event statistics (#198)
Browse files Browse the repository at this point in the history
Basic ringbuf event statistics

This adds a new structure `ebpf_event_stats` where we accumulate stats, right
now it only counts lost events vs non-lost events, but we can grow this in the
future, like adding per type events if it's interesting enough.

The print in EventsTrace is quite primitive as I believe this will only be used
for debugging there, so heh.

Choosing a name for `ebpf_ringbuf_write` was a bit tricky, I wanted to keep the
same parameters but it had to be "different enough" that we could spot it with a
naked eye.

While here, adjust the enum of ebpf events to not skip that precious first bit.
  • Loading branch information
haesbaert committed Jul 3, 2024
1 parent ba15ef6 commit 97581e4
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 33 deletions.
47 changes: 27 additions & 20 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,27 @@
#endif

enum ebpf_event_type {
EBPF_EVENT_PROCESS_FORK = (1 << 1),
EBPF_EVENT_PROCESS_EXEC = (1 << 2),
EBPF_EVENT_PROCESS_EXIT = (1 << 3),
EBPF_EVENT_PROCESS_SETSID = (1 << 4),
EBPF_EVENT_PROCESS_SETUID = (1 << 5),
EBPF_EVENT_PROCESS_SETGID = (1 << 6),
EBPF_EVENT_PROCESS_TTY_WRITE = (1 << 7),
EBPF_EVENT_FILE_DELETE = (1 << 8),
EBPF_EVENT_FILE_CREATE = (1 << 9),
EBPF_EVENT_FILE_RENAME = (1 << 10),
EBPF_EVENT_FILE_MODIFY = (1 << 11),
EBPF_EVENT_FILE_MEMFD_OPEN = (1 << 12),
EBPF_EVENT_FILE_SHMEM_OPEN = (1 << 13),
EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED = (1 << 14),
EBPF_EVENT_NETWORK_CONNECTION_ATTEMPTED = (1 << 15),
EBPF_EVENT_NETWORK_CONNECTION_CLOSED = (1 << 16),
EBPF_EVENT_PROCESS_MEMFD_CREATE = (1 << 17),
EBPF_EVENT_PROCESS_SHMGET = (1 << 18),
EBPF_EVENT_PROCESS_PTRACE = (1 << 19),
EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 20),
EBPF_EVENT_PROCESS_INVALID = 0,
EBPF_EVENT_PROCESS_FORK = (1 << 0),
EBPF_EVENT_PROCESS_EXEC = (1 << 1),
EBPF_EVENT_PROCESS_EXIT = (1 << 2),
EBPF_EVENT_PROCESS_SETSID = (1 << 3),
EBPF_EVENT_PROCESS_SETUID = (1 << 4),
EBPF_EVENT_PROCESS_SETGID = (1 << 5),
EBPF_EVENT_PROCESS_TTY_WRITE = (1 << 6),
EBPF_EVENT_FILE_DELETE = (1 << 7),
EBPF_EVENT_FILE_CREATE = (1 << 8),
EBPF_EVENT_FILE_RENAME = (1 << 9),
EBPF_EVENT_FILE_MODIFY = (1 << 10),
EBPF_EVENT_FILE_MEMFD_OPEN = (1 << 11),
EBPF_EVENT_FILE_SHMEM_OPEN = (1 << 12),
EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED = (1 << 13),
EBPF_EVENT_NETWORK_CONNECTION_ATTEMPTED = (1 << 14),
EBPF_EVENT_NETWORK_CONNECTION_CLOSED = (1 << 15),
EBPF_EVENT_PROCESS_MEMFD_CREATE = (1 << 16),
EBPF_EVENT_PROCESS_SHMGET = (1 << 17),
EBPF_EVENT_PROCESS_PTRACE = (1 << 18),
EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 19),
};

struct ebpf_event_header {
Expand Down Expand Up @@ -378,4 +379,10 @@ struct ebpf_net_event {
char comm[TASK_COMM_LEN];
} __attribute__((packed));

// Basic event statistics
struct ebpf_event_stats {
uint64_t lost; // lost events due to a full ringbuffer
uint64_t sent; // events sent through the ringbuffer
};

#endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H
10 changes: 5 additions & 5 deletions GPL/Events/File/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ static int vfs_unlink__exit(int ret)
size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

// Certain filesystems (eg. overlayfs) call vfs_unlink twice during the same
// execution context.
Expand Down Expand Up @@ -263,10 +263,10 @@ static void prepare_and_send_file_event(struct file *f,
if (path_prefix) {
if ((path_prefix_len > 0) && (size >= path_prefix_len)) {
if (is_equal_prefix(field->data, path_prefix, path_prefix_len))
bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);
}
} else {
bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);
}
}

Expand Down Expand Up @@ -516,7 +516,7 @@ static int vfs_rename__exit(int ret)
size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

// Certain filesystems (eg. overlayfs) call vfs_rename twice during the same
// execution context.
Expand Down Expand Up @@ -588,7 +588,7 @@ static void file_modify_event__emit(enum ebpf_file_change_type typ, struct path
size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return;
Expand Down
21 changes: 21 additions & 0 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,27 @@ static void ebpf_comm__fill(char *comm, size_t len, const struct task_struct *ta
read_kernel_str_or_empty_str(comm, len, BPF_CORE_READ(task, comm));
}

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, u32);
__type(value, struct ebpf_event_stats);
__uint(max_entries, 1);
} ringbuf_stats SEC(".maps");

static long ebpf_ringbuf_write(void *ringbuf, void *data, u64 size, u64 flags)
{
long r;
struct ebpf_event_stats *ees;
u32 zero = 0;

r = bpf_ringbuf_output(ringbuf, data, size, flags);
ees = bpf_map_lookup_elem(&ringbuf_stats, &zero);
if (ees != NULL)
r == 0 ? ees->sent++ : ees->lost++;

return (r);
}

static bool is_kernel_thread(const struct task_struct *task)
{
// All kernel threads are children of kthreadd, which always has pid 2
Expand Down
12 changes: 6 additions & 6 deletions GPL/Events/Process/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ int BPF_PROG(sched_process_fork, const struct task_struct *parent, const struct
size = ebpf_resolve_path_to_string(field->data, &child->fs->pwd, child);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
Expand Down Expand Up @@ -165,7 +165,7 @@ int BPF_PROG(sched_process_exec,
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, binprm->filename);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
Expand Down Expand Up @@ -219,7 +219,7 @@ static int taskstats_exit__enter(const struct task_struct *task, int group_dead)
size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
Expand Down Expand Up @@ -315,7 +315,7 @@ int BPF_PROG(module_load, struct module *mod)
size = read_kernel_str_or_empty_str(field->data, PATH_MAX, mod->srcversion);
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
Expand Down Expand Up @@ -448,7 +448,7 @@ int tracepoint_syscalls_sys_enter_memfd_create(struct trace_event_raw_sys_enter
goto out;
ebpf_vl_field__set_size(&event->vl_fields, field, size);

bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);

out:
return 0;
Expand Down Expand Up @@ -562,7 +562,7 @@ static int output_tty_event(struct ebpf_tty_dev *slave, const void *base, size_t
}

ebpf_vl_field__set_size(&event->vl_fields, field, len_cap);
bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0);
ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);
out:
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion GPL/Events/Varlen.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// We can't use the ringbuf reserve/commit API if we want to output an event
// with variable length fields as we won't know the event size in advance, so
// we create events on the event_buffer_map if this is the case and output them
// with bpf_ringbuf_output.
// with ebpf_ringbuf_write.
//
// If the event has no variable length parameters (i.e. is always a fixed
// size). bpf_ringbuf_reserve/bpf_ringbuf_submit should be used instead to
Expand Down
15 changes: 14 additions & 1 deletion non-GPL/Events/EventsTrace/EventsTrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const char argp_program_doc[] =
"[--process-setgid] [--process-tty-write] [--process-memfd_create] [--process-shmget] "
"[--process-ptrace] [--process-load_module]\n"
"[--net-conn-accept] [--net-conn-attempt] [--net-conn-closed]\n"
"[--print-features-on-init] [--unbuffer-stdout] [--libbpf-verbose]\n";
"[--print-features-on-init] [--stats|-s] [--unbuffer-stdout] [--libbpf-verbose]\n";

// Somewhat kludgy way of ensuring argp doesn't print the EBPF_* constants that
// happen to be valid ASCII values as short options. We pass these enum values
Expand Down Expand Up @@ -120,6 +120,7 @@ static const struct argp_option opts[] = {
"Print network connection closed events", 0},
{"print-features-on-init", 'i', NULL, false,
"Print a message with feature information when probes have been successfully loaded", 1},
{"stats", 's', NULL, false, "Print event statistics", 0},
{"unbuffer-stdout", 'u', NULL, false, "Disable userspace stdout buffering", 2},
{"libbpf-verbose", 'v', NULL, false, "Log verbose libbpf logs to stderr", 2},
{},
Expand All @@ -132,6 +133,7 @@ bool g_print_features_init = 0;
bool g_features_printed = 0;
bool g_unbuffer_stdout = 0;
bool g_libbpf_verbose = 0;
bool g_stats = 0;

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
Expand All @@ -148,6 +150,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
case 'a':
g_events_env = UINT64_MAX;
break;
case 's':
g_stats = 1;
break;
case FILE_DELETE:
case FILE_CREATE:
case FILE_RENAME:
Expand Down Expand Up @@ -1179,6 +1184,14 @@ int main(int argc, char **argv)
fprintf(stderr, "Failed to poll event context %d: %s\n", err, strerror(-err));
break;
}
if (g_stats) {
struct ebpf_event_stats ees;

if (ebpf_event_ctx__read_stats(ctx, &ees) == 0)
printf("sent %lu lost %lu\n", ees.sent, ees.lost);
else
fprintf(stderr, "Failed to read stats: %s\n", strerror(errno));
}
}

ebpf_event_ctx__destroy(&ctx);
Expand Down
22 changes: 22 additions & 0 deletions non-GPL/Events/Lib/EbpfEvents.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,28 @@ int ebpf_event_ctx__poll(struct ebpf_event_ctx *ctx, int timeout)
return ring_buffer__poll(ctx->ringbuf, timeout);
}

int ebpf_event_ctx__read_stats(struct ebpf_event_ctx *ctx, struct ebpf_event_stats *ees)
{
struct ebpf_event_stats pcpu_ees[libbpf_num_possible_cpus()];
uint32_t zero = 0;
int i;

if (!ctx || !ees)
return -1;
if (bpf_map__lookup_elem(ctx->probe->maps.ringbuf_stats, &zero, sizeof(zero), pcpu_ees,
sizeof(pcpu_ees), 0) != 0) {
return -1;
}

memset(ees, 0, sizeof(*ees));
for (i = 0; i < libbpf_num_possible_cpus(); i++) {
ees->lost += pcpu_ees[i].lost;
ees->sent += pcpu_ees[i].sent;
}

return 0;
}

int ebpf_event_ctx__consume(struct ebpf_event_ctx *ctx)
{
if (!ctx)
Expand Down
6 changes: 6 additions & 0 deletions non-GPL/Events/Lib/EbpfEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ int ebpf_event_ctx__next(struct ebpf_event_ctx *ctx, int timeout);
*/
int ebpf_event_ctx__poll(struct ebpf_event_ctx *ctx, int timeout);

/* Read event statistics into ees.
*
* returns 0 on success or less than 0 on failure.
*/
int ebpf_event_ctx__read_stats(struct ebpf_event_ctx *ctx, struct ebpf_event_stats *ees);

/* Consumes as many events as possible from the event context and returns the
* number consumed. Does not poll. This is good if you are polling outside
* this library.
Expand Down

0 comments on commit 97581e4

Please sign in to comment.