Commit 8ac91df6 authored by Daniel T. Lee's avatar Daniel T. Lee Committed by Alexei Starovoitov

samples: bpf: Refactor xdp_monitor with libbpf

To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to change to the libbpf loader
instead of using the bpf_load.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

This commit refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf.
Signed-off-by: default avatarDaniel T. Lee <danieltimlee@gmail.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20201010181734.1109-2-danieltimlee@gmail.com
parent 673e3752
...@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o ...@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
xdp_redirect-objs := xdp_redirect_user.o xdp_redirect-objs := xdp_redirect_user.o
xdp_redirect_map-objs := xdp_redirect_map_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o
xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
xdp_monitor-objs := bpf_load.o xdp_monitor_user.o xdp_monitor-objs := xdp_monitor_user.o
xdp_rxq_info-objs := xdp_rxq_info_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o
syscall_tp-objs := syscall_tp_user.o syscall_tp-objs := syscall_tp_user.o
cpustat-objs := cpustat_user.o cpustat-objs := cpustat_user.o
......
...@@ -26,12 +26,37 @@ static const char *__doc_err_only__= ...@@ -26,12 +26,37 @@ static const char *__doc_err_only__=
#include <net/if.h> #include <net/if.h>
#include <time.h> #include <time.h>
#include <signal.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include "bpf_load.h" #include <bpf/libbpf.h>
#include "bpf_util.h" #include "bpf_util.h"
enum map_type {
REDIRECT_ERR_CNT,
EXCEPTION_CNT,
CPUMAP_ENQUEUE_CNT,
CPUMAP_KTHREAD_CNT,
DEVMAP_XMIT_CNT,
};
static const char *const map_type_strings[] = {
[REDIRECT_ERR_CNT] = "redirect_err_cnt",
[EXCEPTION_CNT] = "exception_cnt",
[CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
[CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
[DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
};
#define NUM_MAP 5
#define NUM_TP 8
static int tp_cnt;
static int map_cnt;
static int verbose = 1; static int verbose = 1;
static bool debug = false; static bool debug = false;
struct bpf_map *map_data[NUM_MAP] = {};
struct bpf_link *tp_links[NUM_TP] = {};
struct bpf_object *obj;
static const struct option long_options[] = { static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' }, {"help", no_argument, NULL, 'h' },
...@@ -41,6 +66,16 @@ static const struct option long_options[] = { ...@@ -41,6 +66,16 @@ static const struct option long_options[] = {
{0, 0, NULL, 0 } {0, 0, NULL, 0 }
}; };
static void int_exit(int sig)
{
/* Detach tracepoints */
while (tp_cnt)
bpf_link__destroy(tp_links[--tp_cnt]);
bpf_object__close(obj);
exit(0);
}
/* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */ /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
#define EXIT_FAIL_MEM 5 #define EXIT_FAIL_MEM 5
...@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec) ...@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec)
* this can happen by someone running perf-record -e * this can happen by someone running perf-record -e
*/ */
fd = map_data[0].fd; /* map0: redirect_err_cnt */ fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
for (i = 0; i < REDIR_RES_MAX; i++) for (i = 0; i < REDIR_RES_MAX; i++)
map_collect_record_u64(fd, i, &rec->xdp_redirect[i]); map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
fd = map_data[1].fd; /* map1: exception_cnt */ fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
for (i = 0; i < XDP_ACTION_MAX; i++) { for (i = 0; i < XDP_ACTION_MAX; i++) {
map_collect_record_u64(fd, i, &rec->xdp_exception[i]); map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
} }
fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */ fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
for (i = 0; i < MAX_CPUS; i++) for (i = 0; i < MAX_CPUS; i++)
map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]); map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */ fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
map_collect_record(fd, 0, &rec->xdp_cpumap_kthread); map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
fd = map_data[4].fd; /* map4: devmap_xmit_cnt */ fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
map_collect_record(fd, 0, &rec->xdp_devmap_xmit); map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
return true; return true;
...@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only) ...@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only)
/* TODO Need more advanced stats on error types */ /* TODO Need more advanced stats on error types */
if (verbose) { if (verbose) {
printf(" - Stats map0: %s\n", map_data[0].name); printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
printf(" - Stats map1: %s\n", map_data[1].name); printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
printf("\n"); printf("\n");
} }
fflush(stdout); fflush(stdout);
...@@ -618,44 +653,51 @@ static void stats_poll(int interval, bool err_only) ...@@ -618,44 +653,51 @@ static void stats_poll(int interval, bool err_only)
static void print_bpf_prog_info(void) static void print_bpf_prog_info(void)
{ {
int i; struct bpf_program *prog;
struct bpf_map *map;
int i = 0;
/* Prog info */ /* Prog info */
printf("Loaded BPF prog have %d bpf program(s)\n", prog_cnt); printf("Loaded BPF prog have %d bpf program(s)\n", tp_cnt);
for (i = 0; i < prog_cnt; i++) { bpf_object__for_each_program(prog, obj) {
printf(" - prog_fd[%d] = fd(%d)\n", i, prog_fd[i]); printf(" - prog_fd[%d] = fd(%d)\n", i, bpf_program__fd(prog));
i++;
} }
i = 0;
/* Maps info */ /* Maps info */
printf("Loaded BPF prog have %d map(s)\n", map_data_count); printf("Loaded BPF prog have %d map(s)\n", map_cnt);
for (i = 0; i < map_data_count; i++) { bpf_object__for_each_map(map, obj) {
char *name = map_data[i].name; const char *name = bpf_map__name(map);
int fd = map_data[i].fd; int fd = bpf_map__fd(map);
printf(" - map_data[%d] = fd(%d) name:%s\n", i, fd, name); printf(" - map_data[%d] = fd(%d) name:%s\n", i, fd, name);
i++;
} }
/* Event info */ /* Event info */
printf("Searching for (max:%d) event file descriptor(s)\n", prog_cnt); printf("Searching for (max:%d) event file descriptor(s)\n", tp_cnt);
for (i = 0; i < prog_cnt; i++) { for (i = 0; i < tp_cnt; i++) {
if (event_fd[i] != -1) int fd = bpf_link__fd(tp_links[i]);
printf(" - event_fd[%d] = fd(%d)\n", i, event_fd[i]);
if (fd != -1)
printf(" - event_fd[%d] = fd(%d)\n", i, fd);
} }
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
struct bpf_program *prog;
int longindex = 0, opt; int longindex = 0, opt;
int ret = EXIT_SUCCESS; int ret = EXIT_FAILURE;
char bpf_obj_file[256]; enum map_type type;
char filename[256];
/* Default settings: */ /* Default settings: */
bool errors_only = true; bool errors_only = true;
int interval = 2; int interval = 2;
snprintf(bpf_obj_file, sizeof(bpf_obj_file), "%s_kern.o", argv[0]);
/* Parse commands line args */ /* Parse commands line args */
while ((opt = getopt_long(argc, argv, "hDSs:", while ((opt = getopt_long(argc, argv, "hDSs:",
long_options, &longindex)) != -1) { long_options, &longindex)) != -1) {
...@@ -672,40 +714,79 @@ int main(int argc, char **argv) ...@@ -672,40 +714,79 @@ int main(int argc, char **argv)
case 'h': case 'h':
default: default:
usage(argv); usage(argv);
return EXIT_FAILURE; return ret;
} }
} }
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
if (setrlimit(RLIMIT_MEMLOCK, &r)) { if (setrlimit(RLIMIT_MEMLOCK, &r)) {
perror("setrlimit(RLIMIT_MEMLOCK)"); perror("setrlimit(RLIMIT_MEMLOCK)");
return EXIT_FAILURE; return ret;
}
/* Remove tracepoint program when program is interrupted or killed */
signal(SIGINT, int_exit);
signal(SIGTERM, int_exit);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
printf("ERROR: opening BPF object file failed\n");
obj = NULL;
goto cleanup;
} }
if (load_bpf_file(bpf_obj_file)) { /* load BPF program */
printf("ERROR - bpf_log_buf: %s", bpf_log_buf); if (bpf_object__load(obj)) {
return EXIT_FAILURE; printf("ERROR: loading BPF object file failed\n");
goto cleanup;
}
for (type = 0; type < NUM_MAP; type++) {
map_data[type] =
bpf_object__find_map_by_name(obj, map_type_strings[type]);
if (libbpf_get_error(map_data[type])) {
printf("ERROR: finding a map in obj file failed\n");
goto cleanup;
} }
if (!prog_fd[0]) { map_cnt++;
printf("ERROR - load_bpf_file: %s\n", strerror(errno)); }
return EXIT_FAILURE;
bpf_object__for_each_program(prog, obj) {
tp_links[tp_cnt] = bpf_program__attach(prog);
if (libbpf_get_error(tp_links[tp_cnt])) {
printf("ERROR: bpf_program__attach failed\n");
tp_links[tp_cnt] = NULL;
goto cleanup;
}
tp_cnt++;
} }
if (debug) { if (debug) {
print_bpf_prog_info(); print_bpf_prog_info();
} }
/* Unload/stop tracepoint event by closing fd's */ /* Unload/stop tracepoint event by closing bpf_link's */
if (errors_only) { if (errors_only) {
/* The prog_fd[i] and event_fd[i] depend on the /* The bpf_link[i] depend on the order of
* order the functions was defined in _kern.c * the functions was defined in _kern.c
*/ */
close(event_fd[2]); /* tracepoint/xdp/xdp_redirect */ bpf_link__destroy(tp_links[2]); /* tracepoint/xdp/xdp_redirect */
close(prog_fd[2]); /* func: trace_xdp_redirect */ tp_links[2] = NULL;
close(event_fd[3]); /* tracepoint/xdp/xdp_redirect_map */
close(prog_fd[3]); /* func: trace_xdp_redirect_map */ bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
tp_links[3] = NULL;
} }
stats_poll(interval, errors_only); stats_poll(interval, errors_only);
ret = EXIT_SUCCESS;
cleanup:
/* Detach tracepoints */
while (tp_cnt)
bpf_link__destroy(tp_links[--tp_cnt]);
bpf_object__close(obj);
return ret; return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment