Skip to content

Commit 52b07e5

Browse files
author
Alexei Starovoitov
committed
Merge branch 'samples: bpf: Refactor XDP programs with libbpf'
"Daniel T. Lee" says: ==================== To avoid confusion caused by the increasing fragmentation of the BPF Loader program, this commit would like to convert the previous bpf_load loader with the libbpf loader. 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. And due to addition of generic bpf_program__attach() to libbpf, it is now possible to attach BPF programs with __attach() instead of explicitly calling __attach_<type>(). This patchset refactors xdp_monitor with using this libbpf API, and the bpf_load is removed and migrated to libbpf. Also, attach_tracepoint() is replaced with the generic __attach() method in xdp_redirect_cpu. Moreover, maps in kern program have been converted to BTF-defined map. --- Changes in v2: - added cleanup logic for bpf_link and bpf_object in xdp_monitor - program section match with bpf_program__is_<type> instead of strncmp - revert BTF key/val type to default of BPF_MAP_TYPE_PERF_EVENT_ARRAY - split increment into seperate satement - refactor pointer array initialization - error code cleanup ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 673e375 + 321f632 commit 52b07e5

File tree

6 files changed

+230
-161
lines changed

6 files changed

+230
-161
lines changed

samples/bpf/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ test_map_in_map-objs := test_map_in_map_user.o
9898
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
101-
xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
102-
xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
101+
xdp_redirect_cpu-objs := xdp_redirect_cpu_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_kern.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@
66
#include <uapi/linux/bpf.h>
77
#include <bpf/bpf_helpers.h>
88

9-
struct bpf_map_def SEC("maps") redirect_err_cnt = {
10-
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
11-
.key_size = sizeof(u32),
12-
.value_size = sizeof(u64),
13-
.max_entries = 2,
9+
struct {
10+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
11+
__type(key, u32);
12+
__type(value, u64);
13+
__uint(max_entries, 2);
1414
/* TODO: have entries for all possible errno's */
15-
};
15+
} redirect_err_cnt SEC(".maps");
1616

1717
#define XDP_UNKNOWN XDP_REDIRECT + 1
18-
struct bpf_map_def SEC("maps") exception_cnt = {
19-
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
20-
.key_size = sizeof(u32),
21-
.value_size = sizeof(u64),
22-
.max_entries = XDP_UNKNOWN + 1,
23-
};
18+
struct {
19+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
20+
__type(key, u32);
21+
__type(value, u64);
22+
__uint(max_entries, XDP_UNKNOWN + 1);
23+
} exception_cnt SEC(".maps");
2424

2525
/* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
2626
* Code in: kernel/include/trace/events/xdp.h
@@ -129,19 +129,19 @@ struct datarec {
129129
};
130130
#define MAX_CPUS 64
131131

132-
struct bpf_map_def SEC("maps") cpumap_enqueue_cnt = {
133-
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
134-
.key_size = sizeof(u32),
135-
.value_size = sizeof(struct datarec),
136-
.max_entries = MAX_CPUS,
137-
};
132+
struct {
133+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
134+
__type(key, u32);
135+
__type(value, struct datarec);
136+
__uint(max_entries, MAX_CPUS);
137+
} cpumap_enqueue_cnt SEC(".maps");
138138

139-
struct bpf_map_def SEC("maps") cpumap_kthread_cnt = {
140-
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
141-
.key_size = sizeof(u32),
142-
.value_size = sizeof(struct datarec),
143-
.max_entries = 1,
144-
};
139+
struct {
140+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
141+
__type(key, u32);
142+
__type(value, struct datarec);
143+
__uint(max_entries, 1);
144+
} cpumap_kthread_cnt SEC(".maps");
145145

146146
/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
147147
* Code in: kernel/include/trace/events/xdp.h
@@ -210,12 +210,12 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx *ctx)
210210
return 0;
211211
}
212212

213-
struct bpf_map_def SEC("maps") devmap_xmit_cnt = {
214-
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
215-
.key_size = sizeof(u32),
216-
.value_size = sizeof(struct datarec),
217-
.max_entries = 1,
218-
};
213+
struct {
214+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
215+
__type(key, u32);
216+
__type(value, struct datarec);
217+
__uint(max_entries, 1);
218+
} devmap_xmit_cnt SEC(".maps");
219219

220220
/* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format
221221
* Code in: kernel/include/trace/events/xdp.h

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)