提交 2365b8f3 编写于 作者: A Andrii Nakryiko 提交者: Zheng Zengkai

libbpf: Add ability to fetch bpf_program's underlying instructions

mainline inclusion
from mainline-5.16-rc1
commit 65a7fa2e
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I5EUVD
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65a7fa2e4e5381d205d3b0098da0fc8471fbbfb6

-------------------------------------------------

Add APIs providing read-only access to bpf_program BPF instructions ([0]).
This is useful for diagnostics purposes, but it also allows a cleaner
support for cloning BPF programs after libbpf did all the FD resolution
and CO-RE relocations, subprog instructions appending, etc. Currently,
cloning BPF program is possible only through hijacking a half-broken
bpf_program__set_prep() API, which doesn't really work well for anything
but most primitive programs. For instance, set_prep() API doesn't allow
adjusting BPF program load parameters which are necessary for loading
fentry/fexit BPF programs (the case where BPF program cloning is
a necessity if doing some sort of mass-attachment functionality).

Given bpf_program__set_prep() API is set to be deprecated, having
a cleaner alternative is a must. libbpf internally already keeps track
of linear array of struct bpf_insn, so it's not hard to expose it. The
only gotcha is that libbpf previously freed instructions array during
bpf_object load time, which would make this API much less useful overall,
because in between bpf_object__open() and bpf_object__load() a lot of
changes to instructions are done by libbpf.

So this patch makes libbpf hold onto prog->insns array even after BPF
program loading. I think this is a small price for added functionality
and improved introspection of BPF program code.

See retsnoop PR ([1]) for how it can be used in practice and code
savings compared to relying on bpf_program__set_prep().

  [0] Closes: https://github.com/libbpf/libbpf/issues/298
  [1] https://github.com/anakryiko/retsnoop/pull/1Signed-off-by: NAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: NAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20211025224531.1088894-3-andrii@kernel.org
(cherry picked from commit 65a7fa2e)
Signed-off-by: NWang Yufen <wangyufen@huawei.com>

Conflicts:
	tools/lib/bpf/libbpf.map
Signed-off-by: NWang Yufen <wangyufen@huawei.com>
上级 f2a6f42e
...@@ -6588,8 +6588,6 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver) ...@@ -6588,8 +6588,6 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver)
out: out:
if (err) if (err)
pr_warn("failed to load program '%s'\n", prog->name); pr_warn("failed to load program '%s'\n", prog->name);
zfree(&prog->insns);
prog->insns_cnt = 0;
return libbpf_err(err); return libbpf_err(err);
} }
...@@ -8060,6 +8058,16 @@ size_t bpf_program__size(const struct bpf_program *prog) ...@@ -8060,6 +8058,16 @@ size_t bpf_program__size(const struct bpf_program *prog)
return prog->insns_cnt * BPF_INSN_SZ; 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, int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
bpf_program_prep_t prep) bpf_program_prep_t prep)
{ {
......
...@@ -219,6 +219,40 @@ LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload ...@@ -219,6 +219,40 @@ 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);
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, LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,
__u32 kern_version); __u32 kern_version);
LIBBPF_API int bpf_program__fd(const struct bpf_program *prog); LIBBPF_API int bpf_program__fd(const struct bpf_program *prog);
...@@ -294,8 +328,6 @@ LIBBPF_API struct bpf_link * ...@@ -294,8 +328,6 @@ LIBBPF_API struct bpf_link *
bpf_program__attach_iter(const struct bpf_program *prog, bpf_program__attach_iter(const struct bpf_program *prog,
const struct bpf_iter_attach_opts *opts); const struct bpf_iter_attach_opts *opts);
struct bpf_insn;
/* /*
* Libbpf allows callers to adjust BPF programs before being loaded * Libbpf allows callers to adjust BPF programs before being loaded
* into kernel. One program in an object file can be transformed into * into kernel. One program in an object file can be transformed into
......
...@@ -384,6 +384,8 @@ LIBBPF_0.5.0 { ...@@ -384,6 +384,8 @@ LIBBPF_0.5.0 {
LIBBPF_0.6.0 { LIBBPF_0.6.0 {
global: global:
bpf_program__insn_cnt;
bpf_program__insns;
btf__add_btf; btf__add_btf;
btf__add_decl_tag; btf__add_decl_tag;
} LIBBPF_0.5.0; } LIBBPF_0.5.0;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册