Skip to content

Commit

Permalink
Merge branch 'libbpf: add bpf_program__insns() accessor'
Browse files Browse the repository at this point in the history
Andrii Nakryiko says:

====================

Add libbpf APIs to access BPF program instructions. Both before and after
libbpf processing (before and after bpf_object__load()). This allows to
inspect what's going on with BPF program assembly instructions as libbpf
performs its processing magic.

But in more practical terms, this allows to do a no-brainer BPF program
cloning, which is something you need when working with fentry/fexit BPF
programs to be able to attach the same BPF program code to multiple kernel
functions. Currently, kernel needs multiple copies of BPF programs, each
loaded with its own target BTF ID. retsnoop is one such example that
previously had to rely on bpf_program__set_prep() API to hijack program
instructions ([0] for before and after).

Speaking of bpf_program__set_prep() API and the whole concept of
multiple-instance BPF programs in libbpf, all that is scheduled for
deprecation in v0.7. It doesn't work well, it's cumbersome, and it will become
more broken as libbpf adds more functionality. So deprecate and remove it in
libbpf 1.0. It doesn't seem to be used by anyone anyways (except for that
retsnoop hack, which is now much cleaner with new APIs as can be seen in [0]).

  [0] https://github.com/anakryiko/retsnoop/pull/1
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Alexei Starovoitov committed Oct 26, 2021
2 parents 9327acd + c4813e9 commit 124c600
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 15 deletions.
36 changes: 24 additions & 12 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5405,7 +5405,7 @@ static int bpf_core_apply_relo(struct bpf_program *prog,
* relocated, so it's enough to just subtract in-section offset
*/
insn_idx = insn_idx - prog->sec_insn_off;
if (insn_idx > prog->insns_cnt)
if (insn_idx >= prog->insns_cnt)
return -EINVAL;
insn = &prog->insns[insn_idx];

Expand Down Expand Up @@ -6653,8 +6653,6 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
out:
if (err)
pr_warn("failed to load program '%s'\n", prog->name);
zfree(&prog->insns);
prog->insns_cnt = 0;
return libbpf_err(err);
}

Expand Down Expand Up @@ -7360,8 +7358,7 @@ static int check_path(const char *path)
return err;
}

int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
int instance)
static int bpf_program_pin_instance(struct bpf_program *prog, const char *path, int instance)
{
char *cp, errmsg[STRERR_BUFSIZE];
int err;
Expand Down Expand Up @@ -7396,8 +7393,7 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
return 0;
}

int bpf_program__unpin_instance(struct bpf_program *prog, const char *path,
int instance)
static int bpf_program_unpin_instance(struct bpf_program *prog, const char *path, int instance)
{
int err;

Expand Down Expand Up @@ -7425,6 +7421,12 @@ int bpf_program__unpin_instance(struct bpf_program *prog, const char *path,
return 0;
}

__attribute__((alias("bpf_program_pin_instance")))
int bpf_object__pin_instance(struct bpf_program *prog, const char *path, int instance);

__attribute__((alias("bpf_program_unpin_instance")))
int bpf_program__unpin_instance(struct bpf_program *prog, const char *path, int instance);

int bpf_program__pin(struct bpf_program *prog, const char *path)
{
int i, err;
Expand All @@ -7449,7 +7451,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)

if (prog->instances.nr == 1) {
/* don't create subdirs when pinning single instance */
return bpf_program__pin_instance(prog, path, 0);
return bpf_program_pin_instance(prog, path, 0);
}

for (i = 0; i < prog->instances.nr; i++) {
Expand All @@ -7465,7 +7467,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
goto err_unpin;
}

err = bpf_program__pin_instance(prog, buf, i);
err = bpf_program_pin_instance(prog, buf, i);
if (err)
goto err_unpin;
}
Expand All @@ -7483,7 +7485,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
else if (len >= PATH_MAX)
continue;

bpf_program__unpin_instance(prog, buf, i);
bpf_program_unpin_instance(prog, buf, i);
}

rmdir(path);
Expand Down Expand Up @@ -7511,7 +7513,7 @@ int bpf_program__unpin(struct bpf_program *prog, const char *path)

if (prog->instances.nr == 1) {
/* don't create subdirs when pinning single instance */
return bpf_program__unpin_instance(prog, path, 0);
return bpf_program_unpin_instance(prog, path, 0);
}

for (i = 0; i < prog->instances.nr; i++) {
Expand All @@ -7524,7 +7526,7 @@ int bpf_program__unpin(struct bpf_program *prog, const char *path)
else if (len >= PATH_MAX)
return libbpf_err(-ENAMETOOLONG);

err = bpf_program__unpin_instance(prog, buf, i);
err = bpf_program_unpin_instance(prog, buf, i);
if (err)
return err;
}
Expand Down Expand Up @@ -8143,6 +8145,16 @@ size_t bpf_program__size(const struct bpf_program *prog)
return prog->insns_cnt * BPF_INSN_SZ;
}

const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog)
{
return prog->insns;
}

size_t bpf_program__insn_cnt(const struct bpf_program *prog)
{
return prog->insns_cnt;
}

int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
bpf_program_prep_t prep)
{
Expand Down
43 changes: 40 additions & 3 deletions tools/lib/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,51 @@ 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 */
LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insn_cnt() instead")
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);

struct bpf_insn;

/**
* @brief **bpf_program__insns()** gives read-only access to BPF program's
* underlying BPF instructions.
* @param prog BPF program for which to return instructions
* @return a pointer to an array of BPF instructions that belong to the
* specified BPF program
*
* Returned pointer is always valid and not NULL. Number of `struct bpf_insn`
* pointed to can be fetched using **bpf_program__insn_cnt()** API.
*
* Keep in mind, libbpf can modify and append/delete BPF program's
* instructions as it processes BPF object file and prepares everything for
* uploading into the kernel. So depending on the point in BPF object
* lifetime, **bpf_program__insns()** can return different sets of
* instructions. As an example, during BPF object load phase BPF program
* instructions will be CO-RE-relocated, BPF subprograms instructions will be
* appended, ldimm64 instructions will have FDs embedded, etc. So instructions
* returned before **bpf_object__load()** and after it might be quite
* different.
*/
LIBBPF_API const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog);
/**
* @brief **bpf_program__insn_cnt()** returns number of `struct bpf_insn`'s
* that form specified BPF program.
* @param prog BPF program for which to return number of BPF instructions
*
* See **bpf_program__insns()** documentation for notes on how libbpf can
* change instructions and their count during different phases of
* **bpf_object** lifetime.
*/
LIBBPF_API size_t bpf_program__insn_cnt(const struct bpf_program *prog);

LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
__u32 kern_version);
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
const char *path,
int instance);
LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
LIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog,
const char *path,
int instance);
Expand Down Expand Up @@ -365,8 +402,6 @@ LIBBPF_API struct bpf_link *
bpf_program__attach_iter(const struct bpf_program *prog,
const struct bpf_iter_attach_opts *opts);

struct bpf_insn;

/*
* Libbpf allows callers to adjust BPF programs before being loaded
* into kernel. One program in an object file can be transformed into
Expand Down Expand Up @@ -395,7 +430,7 @@ struct bpf_insn;
* one instance. In this case bpf_program__fd(prog) is equal to
* bpf_program__nth_fd(prog, 0).
*/

LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insns() for getting bpf_program instructions")
struct bpf_prog_prep_result {
/*
* If not NULL, load new instruction array.
Expand Down Expand Up @@ -424,9 +459,11 @@ typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
struct bpf_insn *insns, int insns_cnt,
struct bpf_prog_prep_result *res);

LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insns() for getting bpf_program instructions")
LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
bpf_program_prep_t prep);

LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated")
LIBBPF_API int bpf_program__nth_fd(const struct bpf_program *prog, int n);

/*
Expand Down
2 changes: 2 additions & 0 deletions tools/lib/bpf/libbpf.map
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ LIBBPF_0.6.0 {
bpf_object__next_program;
bpf_object__prev_map;
bpf_object__prev_program;
bpf_program__insn_cnt;
bpf_program__insns;
btf__add_btf;
btf__add_decl_tag;
btf__raw_data;
Expand Down

0 comments on commit 124c600

Please sign in to comment.