samples: bpf: Refactor kprobe tracing programs with libbpf

For the problem of increasing fragmentation of the bpf loader programs,
instead of using bpf_loader.o, which is used in samples/bpf, this
commit refactors the existing kprobe tracing programs with libbbpf
bpf loader.

    - For kprobe events pointing to system calls, the SYSCALL() macro in
    trace_common.h was used.
    - Adding a kprobe event and attaching a bpf program to it was done
    through bpf_program_attach().
    - Instead of using the existing BPF MAP definition, MAP definition
    has been refactored with the new BTF-defined MAP format.

Signed-off-by: Daniel T. Lee <danieltimlee@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200823085334.9413-3-danieltimlee@gmail.com
This commit is contained in:
Daniel T. Lee 2020-08-23 17:53:33 +09:00 committed by Alexei Starovoitov
parent 35a8b6dd33
commit 3677d0a131
11 changed files with 272 additions and 118 deletions

View File

@ -71,11 +71,11 @@ tracex4-objs := tracex4_user.o
tracex5-objs := tracex5_user.o $(TRACE_HELPERS) tracex5-objs := tracex5_user.o $(TRACE_HELPERS)
tracex6-objs := tracex6_user.o tracex6-objs := tracex6_user.o
tracex7-objs := tracex7_user.o tracex7-objs := tracex7_user.o
test_probe_write_user-objs := bpf_load.o test_probe_write_user_user.o test_probe_write_user-objs := test_probe_write_user_user.o
trace_output-objs := bpf_load.o trace_output_user.o $(TRACE_HELPERS) trace_output-objs := trace_output_user.o $(TRACE_HELPERS)
lathist-objs := bpf_load.o lathist_user.o lathist-objs := lathist_user.o
offwaketime-objs := bpf_load.o offwaketime_user.o $(TRACE_HELPERS) offwaketime-objs := bpf_load.o offwaketime_user.o $(TRACE_HELPERS)
spintest-objs := bpf_load.o spintest_user.o $(TRACE_HELPERS) spintest-objs := spintest_user.o $(TRACE_HELPERS)
map_perf_test-objs := map_perf_test_user.o map_perf_test-objs := map_perf_test_user.o
test_overhead-objs := bpf_load.o test_overhead_user.o test_overhead-objs := bpf_load.o test_overhead_user.o
test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o
@ -86,7 +86,7 @@ xdp1-objs := xdp1_user.o
# reuse xdp1 source intentionally # reuse xdp1 source intentionally
xdp2-objs := xdp1_user.o xdp2-objs := xdp1_user.o
xdp_router_ipv4-objs := xdp_router_ipv4_user.o xdp_router_ipv4-objs := xdp_router_ipv4_user.o
test_current_task_under_cgroup-objs := bpf_load.o $(CGROUP_HELPERS) \ test_current_task_under_cgroup-objs := $(CGROUP_HELPERS) \
test_current_task_under_cgroup_user.o test_current_task_under_cgroup_user.o
trace_event-objs := trace_event_user.o $(TRACE_HELPERS) trace_event-objs := trace_event_user.o $(TRACE_HELPERS)
sampleip-objs := sampleip_user.o $(TRACE_HELPERS) sampleip-objs := sampleip_user.o $(TRACE_HELPERS)

View File

@ -18,12 +18,12 @@
* trace_preempt_[on|off] tracepoints hooks is not supported. * trace_preempt_[on|off] tracepoints hooks is not supported.
*/ */
struct bpf_map_def SEC("maps") my_map = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __type(key, int);
.value_size = sizeof(u64), __type(value, u64);
.max_entries = MAX_CPU, __uint(max_entries, MAX_CPU);
}; } my_map SEC(".maps");
SEC("kprobe/trace_preempt_off") SEC("kprobe/trace_preempt_off")
int bpf_prog1(struct pt_regs *ctx) int bpf_prog1(struct pt_regs *ctx)
@ -61,12 +61,12 @@ static unsigned int log2l(unsigned long v)
return log2(v); return log2(v);
} }
struct bpf_map_def SEC("maps") my_lat = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __type(key, int);
.value_size = sizeof(long), __type(value, long);
.max_entries = MAX_CPU * MAX_ENTRIES, __uint(max_entries, MAX_CPU * MAX_ENTRIES);
}; } my_lat SEC(".maps");
SEC("kprobe/trace_preempt_on") SEC("kprobe/trace_preempt_on")
int bpf_prog2(struct pt_regs *ctx) int bpf_prog2(struct pt_regs *ctx)

View File

@ -6,9 +6,8 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <linux/bpf.h> #include <bpf/libbpf.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_load.h"
#define MAX_ENTRIES 20 #define MAX_ENTRIES 20
#define MAX_CPU 4 #define MAX_CPU 4
@ -81,20 +80,51 @@ static void get_data(int fd)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct bpf_link *links[2];
struct bpf_program *prog;
struct bpf_object *obj;
char filename[256]; char filename[256];
int map_fd, i = 0;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
if (load_bpf_file(filename)) { /* load BPF program */
printf("%s", bpf_log_buf); if (bpf_object__load(obj)) {
return 1; fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_lat");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
bpf_object__for_each_program(prog, obj) {
links[i] = bpf_program__attach(prog);
if (libbpf_get_error(links[i])) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
links[i] = NULL;
goto cleanup;
}
i++;
} }
while (1) { while (1) {
get_data(map_fd[1]); get_data(map_fd);
print_hist(); print_hist();
sleep(5); sleep(5);
} }
cleanup:
for (i--; i >= 0; i--)
bpf_link__destroy(links[i]);
bpf_object__close(obj);
return 0; return 0;
} }

View File

@ -12,25 +12,25 @@
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> #include <bpf/bpf_tracing.h>
struct bpf_map_def SEC("maps") my_map = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(long), __type(key, long);
.value_size = sizeof(long), __type(value, long);
.max_entries = 1024, __uint(max_entries, 1024);
}; } my_map SEC(".maps");
struct bpf_map_def SEC("maps") my_map2 = { struct {
.type = BPF_MAP_TYPE_PERCPU_HASH, __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
.key_size = sizeof(long), __uint(key_size, sizeof(long));
.value_size = sizeof(long), __uint(value_size, sizeof(long));
.max_entries = 1024, __uint(max_entries, 1024);
}; } my_map2 SEC(".maps");
struct bpf_map_def SEC("maps") stackmap = { struct {
.type = BPF_MAP_TYPE_STACK_TRACE, __uint(type, BPF_MAP_TYPE_STACK_TRACE);
.key_size = sizeof(u32), __uint(key_size, sizeof(u32));
.value_size = PERF_MAX_STACK_DEPTH * sizeof(u64), __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64));
.max_entries = 10000, __uint(max_entries, 10000);
}; } stackmap SEC(".maps");
#define PROG(foo) \ #define PROG(foo) \
int foo(struct pt_regs *ctx) \ int foo(struct pt_regs *ctx) \

View File

@ -1,40 +1,77 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <linux/bpf.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include "bpf_load.h" #include <bpf/bpf.h>
#include "trace_helpers.h" #include "trace_helpers.h"
int main(int ac, char **argv) int main(int ac, char **argv)
{ {
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
char filename[256], symbol[256];
struct bpf_object *obj = NULL;
struct bpf_link *links[20];
long key, next_key, value; long key, next_key, value;
char filename[256]; struct bpf_program *prog;
int map_fd, i, j = 0;
const char *title;
struct ksym *sym; struct ksym *sym;
int i;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); if (setrlimit(RLIMIT_MEMLOCK, &r)) {
setrlimit(RLIMIT_MEMLOCK, &r); perror("setrlimit(RLIMIT_MEMLOCK)");
return 1;
}
if (load_kallsyms()) { if (load_kallsyms()) {
printf("failed to process /proc/kallsyms\n"); printf("failed to process /proc/kallsyms\n");
return 2; return 2;
} }
if (load_bpf_file(filename)) { snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
printf("%s", bpf_log_buf); obj = bpf_object__open_file(filename, NULL);
return 1; if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
obj = NULL;
goto cleanup;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
bpf_object__for_each_program(prog, obj) {
title = bpf_program__title(prog, false);
if (sscanf(title, "kprobe/%s", symbol) != 1)
continue;
/* Attach prog only when symbol exists */
if (ksym_get_addr(symbol)) {
links[j] = bpf_program__attach(prog);
if (libbpf_get_error(links[j])) {
fprintf(stderr, "bpf_program__attach failed\n");
links[j] = NULL;
goto cleanup;
}
j++;
}
} }
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
key = 0; key = 0;
printf("kprobing funcs:"); printf("kprobing funcs:");
while (bpf_map_get_next_key(map_fd[0], &key, &next_key) == 0) { while (bpf_map_get_next_key(map_fd, &key, &next_key) == 0) {
bpf_map_lookup_elem(map_fd[0], &next_key, &value); bpf_map_lookup_elem(map_fd, &next_key, &value);
assert(next_key == value); assert(next_key == value);
sym = ksym_search(value); sym = ksym_search(value);
key = next_key; key = next_key;
@ -48,10 +85,15 @@ int main(int ac, char **argv)
if (key) if (key)
printf("\n"); printf("\n");
key = 0; key = 0;
while (bpf_map_get_next_key(map_fd[0], &key, &next_key) == 0) while (bpf_map_get_next_key(map_fd, &key, &next_key) == 0)
bpf_map_delete_elem(map_fd[0], &next_key); bpf_map_delete_elem(map_fd, &next_key);
sleep(1); sleep(1);
} }
cleanup:
for (j--; j >= 0; j--)
bpf_link__destroy(links[j]);
bpf_object__close(obj);
return 0; return 0;
} }

View File

@ -10,23 +10,24 @@
#include <linux/version.h> #include <linux/version.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <uapi/linux/utsname.h> #include <uapi/linux/utsname.h>
#include "trace_common.h"
struct bpf_map_def SEC("maps") cgroup_map = { struct {
.type = BPF_MAP_TYPE_CGROUP_ARRAY, __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
.key_size = sizeof(u32), __uint(key_size, sizeof(u32));
.value_size = sizeof(u32), __uint(value_size, sizeof(u32));
.max_entries = 1, __uint(max_entries, 1);
}; } cgroup_map SEC(".maps");
struct bpf_map_def SEC("maps") perf_map = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(u32), __type(key, u32);
.value_size = sizeof(u64), __type(value, u64);
.max_entries = 1, __uint(max_entries, 1);
}; } perf_map SEC(".maps");
/* Writes the last PID that called sync to a map at index 0 */ /* Writes the last PID that called sync to a map at index 0 */
SEC("kprobe/sys_sync") SEC("kprobe/" SYSCALL(sys_sync))
int bpf_prog1(struct pt_regs *ctx) int bpf_prog1(struct pt_regs *ctx)
{ {
u64 pid = bpf_get_current_pid_tgid(); u64 pid = bpf_get_current_pid_tgid();

View File

@ -4,10 +4,9 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <linux/bpf.h>
#include <unistd.h> #include <unistd.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_load.h" #include <bpf/libbpf.h>
#include "cgroup_helpers.h" #include "cgroup_helpers.h"
#define CGROUP_PATH "/my-cgroup" #define CGROUP_PATH "/my-cgroup"
@ -15,13 +14,44 @@
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
pid_t remote_pid, local_pid = getpid(); pid_t remote_pid, local_pid = getpid();
int cg2, idx = 0, rc = 0; struct bpf_link *link = NULL;
struct bpf_program *prog;
int cg2, idx = 0, rc = 1;
struct bpf_object *obj;
char filename[256]; char filename[256];
int map_fd[2];
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
if (load_bpf_file(filename)) { obj = bpf_object__open_file(filename, NULL);
printf("%s", bpf_log_buf); if (libbpf_get_error(obj)) {
return 1; fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
if (!prog) {
printf("finding a prog in obj file failed\n");
goto cleanup;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd[0] = bpf_object__find_map_fd_by_name(obj, "cgroup_map");
map_fd[1] = bpf_object__find_map_fd_by_name(obj, "perf_map");
if (map_fd[0] < 0 || map_fd[1] < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
link = bpf_program__attach(prog);
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
} }
if (setup_cgroup_environment()) if (setup_cgroup_environment())
@ -70,12 +100,14 @@ int main(int argc, char **argv)
goto err; goto err;
} }
goto out; rc = 0;
err:
rc = 1;
out: err:
close(cg2); close(cg2);
cleanup_cgroup_environment(); cleanup_cgroup_environment();
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return rc; return rc;
} }

View File

@ -13,12 +13,12 @@
#include <bpf/bpf_core_read.h> #include <bpf/bpf_core_read.h>
#include "trace_common.h" #include "trace_common.h"
struct bpf_map_def SEC("maps") dnat_map = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(struct sockaddr_in), __type(key, struct sockaddr_in);
.value_size = sizeof(struct sockaddr_in), __type(value, struct sockaddr_in);
.max_entries = 256, __uint(max_entries, 256);
}; } dnat_map SEC(".maps");
/* kprobe is NOT a stable ABI /* kprobe is NOT a stable ABI
* kernel functions can be removed, renamed or completely change semantics. * kernel functions can be removed, renamed or completely change semantics.

View File

@ -1,21 +1,22 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <linux/bpf.h>
#include <unistd.h> #include <unistd.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_load.h" #include <bpf/libbpf.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <string.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
int main(int ac, char **argv) int main(int ac, char **argv)
{ {
int serverfd, serverconnfd, clientfd;
socklen_t sockaddr_len;
struct sockaddr serv_addr, mapped_addr, tmp_addr;
struct sockaddr_in *serv_addr_in, *mapped_addr_in, *tmp_addr_in; struct sockaddr_in *serv_addr_in, *mapped_addr_in, *tmp_addr_in;
struct sockaddr serv_addr, mapped_addr, tmp_addr;
int serverfd, serverconnfd, clientfd, map_fd;
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct bpf_object *obj;
socklen_t sockaddr_len;
char filename[256]; char filename[256];
char *ip; char *ip;
@ -24,10 +25,35 @@ int main(int ac, char **argv)
tmp_addr_in = (struct sockaddr_in *)&tmp_addr; tmp_addr_in = (struct sockaddr_in *)&tmp_addr;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
if (load_bpf_file(filename)) { prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
printf("%s", bpf_log_buf); if (libbpf_get_error(prog)) {
return 1; fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "dnat_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
link = bpf_program__attach(prog);
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
} }
assert((serverfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); assert((serverfd = socket(AF_INET, SOCK_STREAM, 0)) > 0);
@ -51,7 +77,7 @@ int main(int ac, char **argv)
mapped_addr_in->sin_port = htons(5555); mapped_addr_in->sin_port = htons(5555);
mapped_addr_in->sin_addr.s_addr = inet_addr("255.255.255.255"); mapped_addr_in->sin_addr.s_addr = inet_addr("255.255.255.255");
assert(!bpf_map_update_elem(map_fd[0], &mapped_addr, &serv_addr, BPF_ANY)); assert(!bpf_map_update_elem(map_fd, &mapped_addr, &serv_addr, BPF_ANY));
assert(listen(serverfd, 5) == 0); assert(listen(serverfd, 5) == 0);
@ -75,5 +101,8 @@ int main(int ac, char **argv)
/* Is the server's getsockname = the socket getpeername */ /* Is the server's getsockname = the socket getpeername */
assert(memcmp(&serv_addr, &tmp_addr, sizeof(struct sockaddr_in)) == 0); assert(memcmp(&serv_addr, &tmp_addr, sizeof(struct sockaddr_in)) == 0);
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return 0; return 0;
} }

View File

@ -2,15 +2,16 @@
#include <linux/version.h> #include <linux/version.h>
#include <uapi/linux/bpf.h> #include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include "trace_common.h"
struct bpf_map_def SEC("maps") my_map = { struct {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
.key_size = sizeof(int), __uint(key_size, sizeof(int));
.value_size = sizeof(u32), __uint(value_size, sizeof(u32));
.max_entries = 2, __uint(max_entries, 2);
}; } my_map SEC(".maps");
SEC("kprobe/sys_write") SEC("kprobe/" SYSCALL(sys_write))
int bpf_prog1(struct pt_regs *ctx) int bpf_prog1(struct pt_regs *ctx)
{ {
struct S { struct S {

View File

@ -1,23 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <linux/perf_event.h>
#include <linux/bpf.h>
#include <errno.h>
#include <assert.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <time.h> #include <time.h>
#include <signal.h> #include <signal.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include "bpf_load.h"
#include "perf-sys.h"
static __u64 time_get_ns(void) static __u64 time_get_ns(void)
{ {
@ -57,20 +44,48 @@ static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct perf_buffer_opts pb_opts = {}; struct perf_buffer_opts pb_opts = {};
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct perf_buffer *pb; struct perf_buffer *pb;
struct bpf_object *obj;
int map_fd, ret = 0;
char filename[256]; char filename[256];
FILE *f; FILE *f;
int ret;
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
if (load_bpf_file(filename)) { /* load BPF program */
printf("%s", bpf_log_buf); if (bpf_object__load(obj)) {
return 1; fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
link = bpf_program__attach(prog);
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
} }
pb_opts.sample_cb = print_bpf_output; pb_opts.sample_cb = print_bpf_output;
pb = perf_buffer__new(map_fd[0], 8, &pb_opts); pb = perf_buffer__new(map_fd, 8, &pb_opts);
ret = libbpf_get_error(pb); ret = libbpf_get_error(pb);
if (ret) { if (ret) {
printf("failed to setup perf_buffer: %d\n", ret); printf("failed to setup perf_buffer: %d\n", ret);
@ -84,5 +99,9 @@ int main(int argc, char **argv)
while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) { while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) {
} }
kill(0, SIGINT); kill(0, SIGINT);
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return ret; return ret;
} }