Skip to content

Commit a4702c6

Browse files
DanielTimLeekernel-patches-bot
authored andcommitted
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: Daniel T. Lee <[email protected]>
1 parent 62f10be commit a4702c6

File tree

2 files changed

+121
-40
lines changed

2 files changed

+121
-40
lines changed

samples/bpf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
9999
xdp_redirect-objs := xdp_redirect_user.o
100100
xdp_redirect_map-objs := xdp_redirect_map_user.o
101101
xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
102-
xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
102+
xdp_monitor-objs := xdp_monitor_user.o
103103
xdp_rxq_info-objs := xdp_rxq_info_user.o
104104
syscall_tp-objs := syscall_tp_user.o
105105
cpustat-objs := cpustat_user.o

samples/bpf/xdp_monitor_user.c

Lines changed: 120 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,37 @@ static const char *__doc_err_only__=
2626
#include <net/if.h>
2727
#include <time.h>
2828

29+
#include <signal.h>
2930
#include <bpf/bpf.h>
30-
#include "bpf_load.h"
31+
#include <bpf/libbpf.h>
3132
#include "bpf_util.h"
3233

34+
enum map_type {
35+
REDIRECT_ERR_CNT,
36+
EXCEPTION_CNT,
37+
CPUMAP_ENQUEUE_CNT,
38+
CPUMAP_KTHREAD_CNT,
39+
DEVMAP_XMIT_CNT,
40+
};
41+
42+
static const char *const map_type_strings[] = {
43+
[REDIRECT_ERR_CNT] = "redirect_err_cnt",
44+
[EXCEPTION_CNT] = "exception_cnt",
45+
[CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
46+
[CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
47+
[DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
48+
};
49+
50+
#define NUM_MAP 5
51+
#define NUM_TP 8
52+
53+
static int tp_cnt;
54+
static int map_cnt;
3355
static int verbose = 1;
3456
static bool debug = false;
57+
struct bpf_map *map_data[NUM_MAP] = {};
58+
struct bpf_link *tp_links[NUM_TP] = {};
59+
struct bpf_object *obj;
3560

3661
static const struct option long_options[] = {
3762
{"help", no_argument, NULL, 'h' },
@@ -41,6 +66,16 @@ static const struct option long_options[] = {
4166
{0, 0, NULL, 0 }
4267
};
4368

69+
static void int_exit(int sig)
70+
{
71+
/* Detach tracepoints */
72+
while (tp_cnt)
73+
bpf_link__destroy(tp_links[--tp_cnt]);
74+
75+
bpf_object__close(obj);
76+
exit(0);
77+
}
78+
4479
/* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
4580
#define EXIT_FAIL_MEM 5
4681

@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec)
483518
* this can happen by someone running perf-record -e
484519
*/
485520

486-
fd = map_data[0].fd; /* map0: redirect_err_cnt */
521+
fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
487522
for (i = 0; i < REDIR_RES_MAX; i++)
488523
map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
489524

490-
fd = map_data[1].fd; /* map1: exception_cnt */
525+
fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
491526
for (i = 0; i < XDP_ACTION_MAX; i++) {
492527
map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
493528
}
494529

495-
fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */
530+
fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
496531
for (i = 0; i < MAX_CPUS; i++)
497532
map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
498533

499-
fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */
534+
fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
500535
map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
501536

502-
fd = map_data[4].fd; /* map4: devmap_xmit_cnt */
537+
fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
503538
map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
504539

505540
return true;
@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only)
598633

599634
/* TODO Need more advanced stats on error types */
600635
if (verbose) {
601-
printf(" - Stats map0: %s\n", map_data[0].name);
602-
printf(" - Stats map1: %s\n", map_data[1].name);
636+
printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
637+
printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
603638
printf("\n");
604639
}
605640
fflush(stdout);
@@ -618,44 +653,51 @@ static void stats_poll(int interval, bool err_only)
618653

619654
static void print_bpf_prog_info(void)
620655
{
621-
int i;
656+
struct bpf_program *prog;
657+
struct bpf_map *map;
658+
int i = 0;
622659

623660
/* Prog info */
624-
printf("Loaded BPF prog have %d bpf program(s)\n", prog_cnt);
625-
for (i = 0; i < prog_cnt; i++) {
626-
printf(" - prog_fd[%d] = fd(%d)\n", i, prog_fd[i]);
661+
printf("Loaded BPF prog have %d bpf program(s)\n", tp_cnt);
662+
bpf_object__for_each_program(prog, obj) {
663+
printf(" - prog_fd[%d] = fd(%d)\n", i, bpf_program__fd(prog));
664+
i++;
627665
}
628666

667+
i = 0;
629668
/* Maps info */
630-
printf("Loaded BPF prog have %d map(s)\n", map_data_count);
631-
for (i = 0; i < map_data_count; i++) {
632-
char *name = map_data[i].name;
633-
int fd = map_data[i].fd;
669+
printf("Loaded BPF prog have %d map(s)\n", map_cnt);
670+
bpf_object__for_each_map(map, obj) {
671+
const char *name = bpf_map__name(map);
672+
int fd = bpf_map__fd(map);
634673

635674
printf(" - map_data[%d] = fd(%d) name:%s\n", i, fd, name);
675+
i++;
636676
}
637677

638678
/* Event info */
639-
printf("Searching for (max:%d) event file descriptor(s)\n", prog_cnt);
640-
for (i = 0; i < prog_cnt; i++) {
641-
if (event_fd[i] != -1)
642-
printf(" - event_fd[%d] = fd(%d)\n", i, event_fd[i]);
679+
printf("Searching for (max:%d) event file descriptor(s)\n", tp_cnt);
680+
for (i = 0; i < tp_cnt; i++) {
681+
int fd = bpf_link__fd(tp_links[i]);
682+
683+
if (fd != -1)
684+
printf(" - event_fd[%d] = fd(%d)\n", i, fd);
643685
}
644686
}
645687

646688
int main(int argc, char **argv)
647689
{
648690
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
691+
struct bpf_program *prog;
649692
int longindex = 0, opt;
650-
int ret = EXIT_SUCCESS;
651-
char bpf_obj_file[256];
693+
int ret = EXIT_FAILURE;
694+
enum map_type type;
695+
char filename[256];
652696

653697
/* Default settings: */
654698
bool errors_only = true;
655699
int interval = 2;
656700

657-
snprintf(bpf_obj_file, sizeof(bpf_obj_file), "%s_kern.o", argv[0]);
658-
659701
/* Parse commands line args */
660702
while ((opt = getopt_long(argc, argv, "hDSs:",
661703
long_options, &longindex)) != -1) {
@@ -672,40 +714,79 @@ int main(int argc, char **argv)
672714
case 'h':
673715
default:
674716
usage(argv);
675-
return EXIT_FAILURE;
717+
return ret;
676718
}
677719
}
678720

721+
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
679722
if (setrlimit(RLIMIT_MEMLOCK, &r)) {
680723
perror("setrlimit(RLIMIT_MEMLOCK)");
681-
return EXIT_FAILURE;
724+
return ret;
682725
}
683726

684-
if (load_bpf_file(bpf_obj_file)) {
685-
printf("ERROR - bpf_log_buf: %s", bpf_log_buf);
686-
return EXIT_FAILURE;
727+
/* Remove tracepoint program when program is interrupted or killed */
728+
signal(SIGINT, int_exit);
729+
signal(SIGTERM, int_exit);
730+
731+
obj = bpf_object__open_file(filename, NULL);
732+
if (libbpf_get_error(obj)) {
733+
printf("ERROR: opening BPF object file failed\n");
734+
obj = NULL;
735+
goto cleanup;
736+
}
737+
738+
/* load BPF program */
739+
if (bpf_object__load(obj)) {
740+
printf("ERROR: loading BPF object file failed\n");
741+
goto cleanup;
742+
}
743+
744+
for (type = 0; type < NUM_MAP; type++) {
745+
map_data[type] =
746+
bpf_object__find_map_by_name(obj, map_type_strings[type]);
747+
748+
if (libbpf_get_error(map_data[type])) {
749+
printf("ERROR: finding a map in obj file failed\n");
750+
goto cleanup;
751+
}
752+
map_cnt++;
687753
}
688-
if (!prog_fd[0]) {
689-
printf("ERROR - load_bpf_file: %s\n", strerror(errno));
690-
return EXIT_FAILURE;
754+
755+
bpf_object__for_each_program(prog, obj) {
756+
tp_links[tp_cnt] = bpf_program__attach(prog);
757+
if (libbpf_get_error(tp_links[tp_cnt])) {
758+
printf("ERROR: bpf_program__attach failed\n");
759+
tp_links[tp_cnt] = NULL;
760+
goto cleanup;
761+
}
762+
tp_cnt++;
691763
}
692764

693765
if (debug) {
694766
print_bpf_prog_info();
695767
}
696768

697-
/* Unload/stop tracepoint event by closing fd's */
769+
/* Unload/stop tracepoint event by closing bpf_link's */
698770
if (errors_only) {
699-
/* The prog_fd[i] and event_fd[i] depend on the
700-
* order the functions was defined in _kern.c
771+
/* The bpf_link[i] depend on the order of
772+
* the functions was defined in _kern.c
701773
*/
702-
close(event_fd[2]); /* tracepoint/xdp/xdp_redirect */
703-
close(prog_fd[2]); /* func: trace_xdp_redirect */
704-
close(event_fd[3]); /* tracepoint/xdp/xdp_redirect_map */
705-
close(prog_fd[3]); /* func: trace_xdp_redirect_map */
774+
bpf_link__destroy(tp_links[2]); /* tracepoint/xdp/xdp_redirect */
775+
tp_links[2] = NULL;
776+
777+
bpf_link__destroy(tp_links[3]); /* tracepoint/xdp/xdp_redirect_map */
778+
tp_links[3] = NULL;
706779
}
707780

708781
stats_poll(interval, errors_only);
709782

783+
ret = EXIT_SUCCESS;
784+
785+
cleanup:
786+
/* Detach tracepoints */
787+
while (tp_cnt)
788+
bpf_link__destroy(tp_links[--tp_cnt]);
789+
790+
bpf_object__close(obj);
710791
return ret;
711792
}

0 commit comments

Comments
 (0)