Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic ringbuf event statistics #198

Merged
merged 2 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
haesbaert marked this conversation as resolved.
Show resolved Hide resolved
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
Loading