-
Notifications
You must be signed in to change notification settings - Fork 294
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a simple example of using BPF iterators, which iterates over all tasks on the host. Signed-off-by: Jordan Rome <[email protected]>
- Loading branch information
Showing
6 changed files
with
232 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,5 +10,6 @@ | |
/sockfilter | ||
/tc | ||
/ksyscall | ||
/task_iter | ||
/cmake-build-debug/ | ||
/cmake-build-release/ | ||
/cmake-build-release/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | ||
/* Copyright (c) 2020 Facebook */ | ||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include <bpf/bpf_core_read.h> | ||
#include "task_iter.h" | ||
|
||
char LICENSE[] SEC("license") = "Dual BSD/GPL"; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, __u32); | ||
__type(value, struct task_iter); | ||
} task_iter_buf SEC(".maps"); | ||
|
||
struct task_struct___post514 { | ||
unsigned int __state; | ||
} __attribute__((preserve_access_index)); | ||
|
||
struct task_struct___pre514 { | ||
long state; | ||
} __attribute__((preserve_access_index)); | ||
|
||
__u32 get_task_state(void *arg) | ||
{ | ||
if (bpf_core_field_exists(((struct task_struct___pre514 *)0)->state)) { | ||
struct task_struct___pre514 *task = arg; | ||
return task->state; | ||
} else { | ||
struct task_struct___post514 *task = arg; | ||
return task->__state; | ||
} | ||
} | ||
|
||
SEC("iter/task") | ||
int get_tasks(struct bpf_iter__task *ctx) | ||
{ | ||
struct seq_file *seq = ctx->meta->seq; | ||
struct task_struct *task = ctx->task; | ||
|
||
if (task == (void *)0) { // end | ||
return 0; | ||
} | ||
|
||
__u32 zero = 0; | ||
struct task_iter *t = bpf_map_lookup_elem(&task_iter_buf, &zero); | ||
if (!t) { | ||
return 0; | ||
} | ||
|
||
t->pid = task->tgid; | ||
t->tid = task->pid; | ||
t->state = get_task_state(task); | ||
|
||
bpf_probe_read_kernel_str(t->comm, TASK_COMM_LEN, task->comm); | ||
|
||
int64_t res = bpf_get_task_stack(task, t->kstack, sizeof(__u64) * MAX_STACK_LEN, 0); | ||
if (res <= 0) { | ||
t->kstack_len = 0; | ||
} else { | ||
t->kstack_len = res / sizeof(__u64); | ||
} | ||
|
||
bpf_seq_write(seq, t, sizeof(struct task_iter)); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
/* Copyright (c) 2020 Facebook */ | ||
#include <argp.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <sys/resource.h> | ||
#include <bpf/bpf.h> | ||
#include <bpf/libbpf.h> | ||
#include <unistd.h> | ||
#include "task_iter.h" | ||
#include "task_iter.skel.h" | ||
|
||
static struct env { | ||
bool verbose; | ||
} env; | ||
|
||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) | ||
{ | ||
if (level == LIBBPF_DEBUG && !env.verbose) | ||
return 0; | ||
return vfprintf(stderr, format, args); | ||
} | ||
|
||
static volatile bool exiting = false; | ||
|
||
static void sig_handler(int sig) | ||
{ | ||
exiting = true; | ||
} | ||
|
||
void print_task_state(__u32 state) | ||
{ | ||
// taken from | ||
// https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L85 | ||
// there are a lot more states not covered here but these are common ones | ||
switch (state) { | ||
case 0x0000: | ||
printf("State: RUNNING\n"); | ||
break; | ||
case 0x0001: | ||
printf("State: INTERRUPTIBLE\n"); | ||
break; | ||
case 0x0002: | ||
printf("State: UNINTERRUPTIBLE\n"); | ||
break; | ||
case 0x0200: | ||
printf("State: WAKING\n"); | ||
break; | ||
case 0x0400: | ||
printf("State: NOLOAD\n"); | ||
break; | ||
case 0x0402: | ||
printf("State: IDLE\n"); | ||
break; | ||
case 0x0800: | ||
printf("State: NEW\n"); | ||
break; | ||
default: | ||
printf("Unknown Task state\n"); | ||
} | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct task_iter_bpf *skel; | ||
int err; | ||
int get_tasks_fd; | ||
|
||
/* Set up libbpf errors and debug info callback */ | ||
libbpf_set_print(libbpf_print_fn); | ||
|
||
/* Cleaner handling of Ctrl-C */ | ||
signal(SIGINT, sig_handler); | ||
signal(SIGTERM, sig_handler); | ||
|
||
/* Load and verify BPF application */ | ||
skel = task_iter_bpf__open(); | ||
if (!skel) { | ||
fprintf(stderr, "Failed to open and load BPF skeleton\n"); | ||
return 1; | ||
} | ||
|
||
/* Load & verify BPF programs */ | ||
err = task_iter_bpf__load(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to load and verify BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
/* Attach tracepoints */ | ||
err = task_iter_bpf__attach(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to attach BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
get_tasks_fd = bpf_iter_create(bpf_link__fd(skel->links.get_tasks)); | ||
if (!get_tasks_fd) { | ||
err = -1; | ||
fprintf(stderr, "Failed to create iter\n"); | ||
goto cleanup; | ||
} | ||
|
||
struct task_iter buf; | ||
ssize_t ret; | ||
|
||
while (true) { | ||
ret = read(get_tasks_fd, &buf, sizeof(struct task_iter)); | ||
if (ret < 0) { | ||
if (errno == EAGAIN) { | ||
continue; | ||
} | ||
err = -errno; | ||
break; | ||
} | ||
if (ret == 0) { | ||
break; | ||
} | ||
printf("Task Info. Pid: %d. Process Name: %s. Kernel Stack Len: %d. ", buf.pid, | ||
buf.comm, buf.kstack_len); | ||
print_task_state(buf.state); | ||
} | ||
|
||
cleanup: | ||
/* Clean up */ | ||
close(get_tasks_fd); | ||
task_iter_bpf__destroy(skel); | ||
|
||
return err < 0 ? -err : 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ | ||
/* Copyright (c) 2020 Facebook */ | ||
|
||
#define TASK_COMM_LEN 16 | ||
#define MAX_STACK_LEN 127 | ||
|
||
struct task_iter { | ||
pid_t pid; | ||
pid_t tid; | ||
__u32 state; | ||
char comm[TASK_COMM_LEN]; | ||
|
||
int kstack_len; | ||
|
||
__u64 kstack[MAX_STACK_LEN]; | ||
}; |