Skip to content

Commit d7a18ea

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: Add generic bpf_program__attach()
Generalize BPF program attaching and allow libbpf to auto-detect type (and extra parameters, where applicable) and attach supported BPF program types based on program sections. Currently this is supported for: - kprobe/kretprobe; - tracepoint; - raw tracepoint; - tracing programs (typed raw TP/fentry/fexit). More types support can be trivially added within this framework. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 0d13bfc commit d7a18ea

File tree

4 files changed

+153
-38
lines changed

4 files changed

+153
-38
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 147 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4972,33 +4972,69 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
49724972
*/
49734973
#define BPF_APROG_COMPAT(string, ptype) BPF_PROG_SEC(string, ptype)
49744974

4975-
static const struct {
4975+
#define SEC_DEF(sec_pfx, ptype, ...) { \
4976+
.sec = sec_pfx, \
4977+
.len = sizeof(sec_pfx) - 1, \
4978+
.prog_type = BPF_PROG_TYPE_##ptype, \
4979+
__VA_ARGS__ \
4980+
}
4981+
4982+
struct bpf_sec_def;
4983+
4984+
typedef struct bpf_link *(*attach_fn_t)(const struct bpf_sec_def *sec,
4985+
struct bpf_program *prog);
4986+
4987+
static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
4988+
struct bpf_program *prog);
4989+
static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
4990+
struct bpf_program *prog);
4991+
static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
4992+
struct bpf_program *prog);
4993+
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
4994+
struct bpf_program *prog);
4995+
4996+
struct bpf_sec_def {
49764997
const char *sec;
49774998
size_t len;
49784999
enum bpf_prog_type prog_type;
49795000
enum bpf_attach_type expected_attach_type;
49805001
bool is_attachable;
49815002
bool is_attach_btf;
49825003
enum bpf_attach_type attach_type;
4983-
} section_names[] = {
5004+
attach_fn_t attach_fn;
5005+
};
5006+
5007+
static const struct bpf_sec_def section_defs[] = {
49845008
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
49855009
BPF_PROG_SEC("sk_reuseport", BPF_PROG_TYPE_SK_REUSEPORT),
4986-
BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE),
5010+
SEC_DEF("kprobe/", KPROBE,
5011+
.attach_fn = attach_kprobe),
49875012
BPF_PROG_SEC("uprobe/", BPF_PROG_TYPE_KPROBE),
4988-
BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE),
5013+
SEC_DEF("kretprobe/", KPROBE,
5014+
.attach_fn = attach_kprobe),
49895015
BPF_PROG_SEC("uretprobe/", BPF_PROG_TYPE_KPROBE),
49905016
BPF_PROG_SEC("classifier", BPF_PROG_TYPE_SCHED_CLS),
49915017
BPF_PROG_SEC("action", BPF_PROG_TYPE_SCHED_ACT),
4992-
BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT),
4993-
BPF_PROG_SEC("tp/", BPF_PROG_TYPE_TRACEPOINT),
4994-
BPF_PROG_SEC("raw_tracepoint/", BPF_PROG_TYPE_RAW_TRACEPOINT),
4995-
BPF_PROG_SEC("raw_tp/", BPF_PROG_TYPE_RAW_TRACEPOINT),
4996-
BPF_PROG_BTF("tp_btf/", BPF_PROG_TYPE_TRACING,
4997-
BPF_TRACE_RAW_TP),
4998-
BPF_PROG_BTF("fentry/", BPF_PROG_TYPE_TRACING,
4999-
BPF_TRACE_FENTRY),
5000-
BPF_PROG_BTF("fexit/", BPF_PROG_TYPE_TRACING,
5001-
BPF_TRACE_FEXIT),
5018+
SEC_DEF("tracepoint/", TRACEPOINT,
5019+
.attach_fn = attach_tp),
5020+
SEC_DEF("tp/", TRACEPOINT,
5021+
.attach_fn = attach_tp),
5022+
SEC_DEF("raw_tracepoint/", RAW_TRACEPOINT,
5023+
.attach_fn = attach_raw_tp),
5024+
SEC_DEF("raw_tp/", RAW_TRACEPOINT,
5025+
.attach_fn = attach_raw_tp),
5026+
SEC_DEF("tp_btf/", TRACING,
5027+
.expected_attach_type = BPF_TRACE_RAW_TP,
5028+
.is_attach_btf = true,
5029+
.attach_fn = attach_trace),
5030+
SEC_DEF("fentry/", TRACING,
5031+
.expected_attach_type = BPF_TRACE_FENTRY,
5032+
.is_attach_btf = true,
5033+
.attach_fn = attach_trace),
5034+
SEC_DEF("fexit/", TRACING,
5035+
.expected_attach_type = BPF_TRACE_FEXIT,
5036+
.is_attach_btf = true,
5037+
.attach_fn = attach_trace),
50025038
BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP),
50035039
BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT),
50045040
BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN),
@@ -5060,12 +5096,26 @@ static const struct {
50605096
#undef BPF_APROG_SEC
50615097
#undef BPF_EAPROG_SEC
50625098
#undef BPF_APROG_COMPAT
5099+
#undef SEC_DEF
50635100

50645101
#define MAX_TYPE_NAME_SIZE 32
50655102

5103+
static const struct bpf_sec_def *find_sec_def(const char *sec_name)
5104+
{
5105+
int i, n = ARRAY_SIZE(section_defs);
5106+
5107+
for (i = 0; i < n; i++) {
5108+
if (strncmp(sec_name,
5109+
section_defs[i].sec, section_defs[i].len))
5110+
continue;
5111+
return &section_defs[i];
5112+
}
5113+
return NULL;
5114+
}
5115+
50665116
static char *libbpf_get_type_names(bool attach_type)
50675117
{
5068-
int i, len = ARRAY_SIZE(section_names) * MAX_TYPE_NAME_SIZE;
5118+
int i, len = ARRAY_SIZE(section_defs) * MAX_TYPE_NAME_SIZE;
50695119
char *buf;
50705120

50715121
buf = malloc(len);
@@ -5074,16 +5124,16 @@ static char *libbpf_get_type_names(bool attach_type)
50745124

50755125
buf[0] = '\0';
50765126
/* Forge string buf with all available names */
5077-
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
5078-
if (attach_type && !section_names[i].is_attachable)
5127+
for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
5128+
if (attach_type && !section_defs[i].is_attachable)
50795129
continue;
50805130

5081-
if (strlen(buf) + strlen(section_names[i].sec) + 2 > len) {
5131+
if (strlen(buf) + strlen(section_defs[i].sec) + 2 > len) {
50825132
free(buf);
50835133
return NULL;
50845134
}
50855135
strcat(buf, " ");
5086-
strcat(buf, section_names[i].sec);
5136+
strcat(buf, section_defs[i].sec);
50875137
}
50885138

50895139
return buf;
@@ -5092,19 +5142,19 @@ static char *libbpf_get_type_names(bool attach_type)
50925142
int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
50935143
enum bpf_attach_type *expected_attach_type)
50945144
{
5145+
const struct bpf_sec_def *sec_def;
50955146
char *type_names;
5096-
int i;
50975147

50985148
if (!name)
50995149
return -EINVAL;
51005150

5101-
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
5102-
if (strncmp(name, section_names[i].sec, section_names[i].len))
5103-
continue;
5104-
*prog_type = section_names[i].prog_type;
5105-
*expected_attach_type = section_names[i].expected_attach_type;
5151+
sec_def = find_sec_def(name);
5152+
if (sec_def) {
5153+
*prog_type = sec_def->prog_type;
5154+
*expected_attach_type = sec_def->expected_attach_type;
51065155
return 0;
51075156
}
5157+
51085158
pr_warn("failed to guess program type from ELF section '%s'\n", name);
51095159
type_names = libbpf_get_type_names(false);
51105160
if (type_names != NULL) {
@@ -5187,16 +5237,16 @@ static int libbpf_find_attach_btf_id(const char *name,
51875237
if (!name)
51885238
return -EINVAL;
51895239

5190-
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
5191-
if (!section_names[i].is_attach_btf)
5240+
for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
5241+
if (!section_defs[i].is_attach_btf)
51925242
continue;
5193-
if (strncmp(name, section_names[i].sec, section_names[i].len))
5243+
if (strncmp(name, section_defs[i].sec, section_defs[i].len))
51945244
continue;
51955245
if (attach_prog_fd)
5196-
err = libbpf_find_prog_btf_id(name + section_names[i].len,
5246+
err = libbpf_find_prog_btf_id(name + section_defs[i].len,
51975247
attach_prog_fd);
51985248
else
5199-
err = libbpf_find_vmlinux_btf_id(name + section_names[i].len,
5249+
err = libbpf_find_vmlinux_btf_id(name + section_defs[i].len,
52005250
attach_type);
52015251
if (err <= 0)
52025252
pr_warn("%s is not found in vmlinux BTF\n", name);
@@ -5215,12 +5265,12 @@ int libbpf_attach_type_by_name(const char *name,
52155265
if (!name)
52165266
return -EINVAL;
52175267

5218-
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
5219-
if (strncmp(name, section_names[i].sec, section_names[i].len))
5268+
for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
5269+
if (strncmp(name, section_defs[i].sec, section_defs[i].len))
52205270
continue;
5221-
if (!section_names[i].is_attachable)
5271+
if (!section_defs[i].is_attachable)
52225272
return -EINVAL;
5223-
*attach_type = section_names[i].attach_type;
5273+
*attach_type = section_defs[i].attach_type;
52245274
return 0;
52255275
}
52265276
pr_warn("failed to guess attach type based on ELF section name '%s'\n", name);
@@ -5680,6 +5730,18 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
56805730
return link;
56815731
}
56825732

5733+
static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
5734+
struct bpf_program *prog)
5735+
{
5736+
const char *func_name;
5737+
bool retprobe;
5738+
5739+
func_name = bpf_program__title(prog, false) + sec->len;
5740+
retprobe = strcmp(sec->sec, "kretprobe/") == 0;
5741+
5742+
return bpf_program__attach_kprobe(prog, retprobe, func_name);
5743+
}
5744+
56835745
struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,
56845746
bool retprobe, pid_t pid,
56855747
const char *binary_path,
@@ -5792,6 +5854,32 @@ struct bpf_link *bpf_program__attach_tracepoint(struct bpf_program *prog,
57925854
return link;
57935855
}
57945856

5857+
static struct bpf_link *attach_tp(const struct bpf_sec_def *sec,
5858+
struct bpf_program *prog)
5859+
{
5860+
char *sec_name, *tp_cat, *tp_name;
5861+
struct bpf_link *link;
5862+
5863+
sec_name = strdup(bpf_program__title(prog, false));
5864+
if (!sec_name)
5865+
return ERR_PTR(-ENOMEM);
5866+
5867+
/* extract "tp/<category>/<name>" */
5868+
tp_cat = sec_name + sec->len;
5869+
tp_name = strchr(tp_cat, '/');
5870+
if (!tp_name) {
5871+
link = ERR_PTR(-EINVAL);
5872+
goto out;
5873+
}
5874+
*tp_name = '\0';
5875+
tp_name++;
5876+
5877+
link = bpf_program__attach_tracepoint(prog, tp_cat, tp_name);
5878+
out:
5879+
free(sec_name);
5880+
return link;
5881+
}
5882+
57955883
static int bpf_link__destroy_fd(struct bpf_link *link)
57965884
{
57975885
struct bpf_link_fd *l = (void *)link;
@@ -5831,6 +5919,14 @@ struct bpf_link *bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
58315919
return (struct bpf_link *)link;
58325920
}
58335921

5922+
static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec,
5923+
struct bpf_program *prog)
5924+
{
5925+
const char *tp_name = bpf_program__title(prog, false) + sec->len;
5926+
5927+
return bpf_program__attach_raw_tracepoint(prog, tp_name);
5928+
}
5929+
58345930
struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
58355931
{
58365932
char errmsg[STRERR_BUFSIZE];
@@ -5862,6 +5958,23 @@ struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
58625958
return (struct bpf_link *)link;
58635959
}
58645960

5961+
static struct bpf_link *attach_trace(const struct bpf_sec_def *sec,
5962+
struct bpf_program *prog)
5963+
{
5964+
return bpf_program__attach_trace(prog);
5965+
}
5966+
5967+
struct bpf_link *bpf_program__attach(struct bpf_program *prog)
5968+
{
5969+
const struct bpf_sec_def *sec_def;
5970+
5971+
sec_def = find_sec_def(bpf_program__title(prog, false));
5972+
if (!sec_def || !sec_def->attach_fn)
5973+
return ERR_PTR(-ESRCH);
5974+
5975+
return sec_def->attach_fn(sec_def, prog);
5976+
}
5977+
58655978
enum bpf_perf_event_ret
58665979
bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
58675980
void **copy_mem, size_t *copy_size,

tools/lib/bpf/libbpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ struct bpf_link;
237237

238238
LIBBPF_API int bpf_link__destroy(struct bpf_link *link);
239239

240+
LIBBPF_API struct bpf_link *
241+
bpf_program__attach(struct bpf_program *prog);
240242
LIBBPF_API struct bpf_link *
241243
bpf_program__attach_perf_event(struct bpf_program *prog, int pfd);
242244
LIBBPF_API struct bpf_link *

tools/lib/bpf/libbpf.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,6 @@ LIBBPF_0.0.6 {
210210
} LIBBPF_0.0.5;
211211

212212
LIBBPF_0.0.7 {
213+
global:
214+
bpf_program__attach;
213215
} LIBBPF_0.0.6;

tools/testing/selftests/bpf/prog_tests/probe_user.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33

44
void test_probe_user(void)
55
{
6-
#define kprobe_name "__sys_connect"
7-
const char *prog_name = "kprobe/" kprobe_name;
6+
const char *prog_name = "kprobe/__sys_connect";
87
const char *obj_file = "./test_probe_user.o";
98
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, );
109
int err, results_map_fd, sock_fd, duration = 0;
@@ -33,8 +32,7 @@ void test_probe_user(void)
3332
"err %d\n", results_map_fd))
3433
goto cleanup;
3534

36-
kprobe_link = bpf_program__attach_kprobe(kprobe_prog, false,
37-
kprobe_name);
35+
kprobe_link = bpf_program__attach(kprobe_prog);
3836
if (CHECK(IS_ERR(kprobe_link), "attach_kprobe",
3937
"err %ld\n", PTR_ERR(kprobe_link))) {
4038
kprobe_link = NULL;

0 commit comments

Comments
 (0)