Commit afa12644 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'libbpf_autoload_knob'

Andrii Nakryiko says:

====================
Add ability to turn off default auto-loading of each BPF program by libbpf on
BPF object load. This is the feature that allows BPF applications to have
optional functionality, which is only excercised on kernel that support
necessary features, while falling back to reduced/less performant
functionality, if kernel is outdated.
====================
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 16d37ee3 5712174c
...@@ -230,6 +230,7 @@ struct bpf_program { ...@@ -230,6 +230,7 @@ struct bpf_program {
struct bpf_insn *insns; struct bpf_insn *insns;
size_t insns_cnt, main_prog_cnt; size_t insns_cnt, main_prog_cnt;
enum bpf_prog_type type; enum bpf_prog_type type;
bool load;
struct reloc_desc *reloc_desc; struct reloc_desc *reloc_desc;
int nr_reloc; int nr_reloc;
...@@ -541,6 +542,7 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx, ...@@ -541,6 +542,7 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
prog->instances.fds = NULL; prog->instances.fds = NULL;
prog->instances.nr = -1; prog->instances.nr = -1;
prog->type = BPF_PROG_TYPE_UNSPEC; prog->type = BPF_PROG_TYPE_UNSPEC;
prog->load = true;
return 0; return 0;
errout: errout:
...@@ -2513,6 +2515,8 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj) ...@@ -2513,6 +2515,8 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj)
need_vmlinux_btf = true; need_vmlinux_btf = true;
bpf_object__for_each_program(prog, obj) { bpf_object__for_each_program(prog, obj) {
if (!prog->load)
continue;
if (libbpf_prog_needs_vmlinux_btf(prog)) { if (libbpf_prog_needs_vmlinux_btf(prog)) {
need_vmlinux_btf = true; need_vmlinux_btf = true;
break; break;
...@@ -5445,6 +5449,12 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver) ...@@ -5445,6 +5449,12 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
{ {
int err = 0, fd, i, btf_id; int err = 0, fd, i, btf_id;
if (prog->obj->loaded) {
pr_warn("prog '%s'('%s'): can't load after object was loaded\n",
prog->name, prog->section_name);
return -EINVAL;
}
if ((prog->type == BPF_PROG_TYPE_TRACING || if ((prog->type == BPF_PROG_TYPE_TRACING ||
prog->type == BPF_PROG_TYPE_LSM || prog->type == BPF_PROG_TYPE_LSM ||
prog->type == BPF_PROG_TYPE_EXT) && !prog->attach_btf_id) { prog->type == BPF_PROG_TYPE_EXT) && !prog->attach_btf_id) {
...@@ -5533,16 +5543,21 @@ static bool bpf_program__is_function_storage(const struct bpf_program *prog, ...@@ -5533,16 +5543,21 @@ static bool bpf_program__is_function_storage(const struct bpf_program *prog,
static int static int
bpf_object__load_progs(struct bpf_object *obj, int log_level) bpf_object__load_progs(struct bpf_object *obj, int log_level)
{ {
struct bpf_program *prog;
size_t i; size_t i;
int err; int err;
for (i = 0; i < obj->nr_programs; i++) { for (i = 0; i < obj->nr_programs; i++) {
if (bpf_program__is_function_storage(&obj->programs[i], obj)) prog = &obj->programs[i];
if (bpf_program__is_function_storage(prog, obj))
continue; continue;
obj->programs[i].log_level |= log_level; if (!prog->load) {
err = bpf_program__load(&obj->programs[i], pr_debug("prog '%s'('%s'): skipped loading\n",
obj->license, prog->name, prog->section_name);
obj->kern_version); continue;
}
prog->log_level |= log_level;
err = bpf_program__load(prog, obj->license, obj->kern_version);
if (err) if (err)
return err; return err;
} }
...@@ -5869,12 +5884,10 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) ...@@ -5869,12 +5884,10 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
return -EINVAL; return -EINVAL;
if (obj->loaded) { if (obj->loaded) {
pr_warn("object should not be loaded twice\n"); pr_warn("object '%s': load can't be attempted twice\n", obj->name);
return -EINVAL; return -EINVAL;
} }
obj->loaded = true;
err = bpf_object__probe_loading(obj); err = bpf_object__probe_loading(obj);
err = err ? : bpf_object__probe_caps(obj); err = err ? : bpf_object__probe_caps(obj);
err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); err = err ? : bpf_object__resolve_externs(obj, obj->kconfig);
...@@ -5889,6 +5902,8 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) ...@@ -5889,6 +5902,8 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
btf__free(obj->btf_vmlinux); btf__free(obj->btf_vmlinux);
obj->btf_vmlinux = NULL; obj->btf_vmlinux = NULL;
obj->loaded = true; /* doesn't matter if successfully or not */
if (err) if (err)
goto out; goto out;
...@@ -6661,6 +6676,20 @@ const char *bpf_program__title(const struct bpf_program *prog, bool needs_copy) ...@@ -6661,6 +6676,20 @@ const char *bpf_program__title(const struct bpf_program *prog, bool needs_copy)
return title; return title;
} }
bool bpf_program__autoload(const struct bpf_program *prog)
{
return prog->load;
}
int bpf_program__set_autoload(struct bpf_program *prog, bool autoload)
{
if (prog->obj->loaded)
return -EINVAL;
prog->load = autoload;
return 0;
}
int bpf_program__fd(const struct bpf_program *prog) int bpf_program__fd(const struct bpf_program *prog)
{ {
return bpf_program__nth_fd(prog, 0); return bpf_program__nth_fd(prog, 0);
...@@ -9283,6 +9312,9 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) ...@@ -9283,6 +9312,9 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s)
const struct bpf_sec_def *sec_def; const struct bpf_sec_def *sec_def;
const char *sec_name = bpf_program__title(prog, false); const char *sec_name = bpf_program__title(prog, false);
if (!prog->load)
continue;
sec_def = find_sec_def(sec_name); sec_def = find_sec_def(sec_name);
if (!sec_def || !sec_def->attach_fn) if (!sec_def || !sec_def->attach_fn)
continue; continue;
......
...@@ -200,6 +200,8 @@ LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog, ...@@ -200,6 +200,8 @@ LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog); LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog);
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog, LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
bool needs_copy); bool needs_copy);
LIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);
LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);
/* returns program size in bytes */ /* returns program size in bytes */
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog); LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);
......
...@@ -286,4 +286,6 @@ LIBBPF_0.1.0 { ...@@ -286,4 +286,6 @@ LIBBPF_0.1.0 {
bpf_map__set_value_size; bpf_map__set_value_size;
bpf_map__type; bpf_map__type;
bpf_map__value_size; bpf_map__value_size;
bpf_program__autoload;
bpf_program__set_autoload;
} LIBBPF_0.0.9; } LIBBPF_0.0.9;
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
#include <test_progs.h>
#include <time.h>
#include "test_autoload.skel.h"
void test_autoload(void)
{
int duration = 0, err;
struct test_autoload* skel;
skel = test_autoload__open_and_load();
/* prog3 should be broken */
if (CHECK(skel, "skel_open_and_load", "unexpected success\n"))
goto cleanup;
skel = test_autoload__open();
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
goto cleanup;
/* don't load prog3 */
bpf_program__set_autoload(skel->progs.prog3, false);
err = test_autoload__load(skel);
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
goto cleanup;
err = test_autoload__attach(skel);
if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
goto cleanup;
usleep(1);
CHECK(!skel->bss->prog1_called, "prog1", "not called\n");
CHECK(!skel->bss->prog2_called, "prog2", "not called\n");
CHECK(skel->bss->prog3_called, "prog3", "called?!\n");
cleanup:
test_autoload__destroy(skel);
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
bool prog1_called = false;
bool prog2_called = false;
bool prog3_called = false;
SEC("raw_tp/sys_enter")
int prog1(const void *ctx)
{
prog1_called = true;
return 0;
}
SEC("raw_tp/sys_exit")
int prog2(const void *ctx)
{
prog2_called = true;
return 0;
}
struct fake_kernel_struct {
int whatever;
} __attribute__((preserve_access_index));
SEC("fentry/unexisting-kprobe-will-fail-if-loaded")
int prog3(const void *ctx)
{
struct fake_kernel_struct *fake = (void *)ctx;
fake->whatever = 123;
prog3_called = true;
return 0;
}
char _license[] SEC("license") = "GPL";
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