Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'libbpf: add bpf_program__insns() accessor'

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>

+66 -15
+24 -12
tools/lib/bpf/libbpf.c
··· 5405 5405 * relocated, so it's enough to just subtract in-section offset 5406 5406 */ 5407 5407 insn_idx = insn_idx - prog->sec_insn_off; 5408 - if (insn_idx > prog->insns_cnt) 5408 + if (insn_idx >= prog->insns_cnt) 5409 5409 return -EINVAL; 5410 5410 insn = &prog->insns[insn_idx]; 5411 5411 ··· 6653 6653 out: 6654 6654 if (err) 6655 6655 pr_warn("failed to load program '%s'\n", prog->name); 6656 - zfree(&prog->insns); 6657 - prog->insns_cnt = 0; 6658 6656 return libbpf_err(err); 6659 6657 } 6660 6658 ··· 7358 7360 return err; 7359 7361 } 7360 7362 7361 - int bpf_program__pin_instance(struct bpf_program *prog, const char *path, 7362 - int instance) 7363 + static int bpf_program_pin_instance(struct bpf_program *prog, const char *path, int instance) 7363 7364 { 7364 7365 char *cp, errmsg[STRERR_BUFSIZE]; 7365 7366 int err; ··· 7393 7396 return 0; 7394 7397 } 7395 7398 7396 - int bpf_program__unpin_instance(struct bpf_program *prog, const char *path, 7397 - int instance) 7399 + static int bpf_program_unpin_instance(struct bpf_program *prog, const char *path, int instance) 7398 7400 { 7399 7401 int err; 7400 7402 ··· 7421 7425 return 0; 7422 7426 } 7423 7427 7428 + __attribute__((alias("bpf_program_pin_instance"))) 7429 + int bpf_object__pin_instance(struct bpf_program *prog, const char *path, int instance); 7430 + 7431 + __attribute__((alias("bpf_program_unpin_instance"))) 7432 + int bpf_program__unpin_instance(struct bpf_program *prog, const char *path, int instance); 7433 + 7424 7434 int bpf_program__pin(struct bpf_program *prog, const char *path) 7425 7435 { 7426 7436 int i, err; ··· 7451 7449 7452 7450 if (prog->instances.nr == 1) { 7453 7451 /* don't create subdirs when pinning single instance */ 7454 - return bpf_program__pin_instance(prog, path, 0); 7452 + return bpf_program_pin_instance(prog, path, 0); 7455 7453 } 7456 7454 7457 7455 for (i = 0; i < prog->instances.nr; i++) { ··· 7467 7465 goto err_unpin; 7468 7466 } 7469 7467 7470 - err = bpf_program__pin_instance(prog, buf, i); 7468 + err = bpf_program_pin_instance(prog, buf, i); 7471 7469 if (err) 7472 7470 goto err_unpin; 7473 7471 } ··· 7485 7483 else if (len >= PATH_MAX) 7486 7484 continue; 7487 7485 7488 - bpf_program__unpin_instance(prog, buf, i); 7486 + bpf_program_unpin_instance(prog, buf, i); 7489 7487 } 7490 7488 7491 7489 rmdir(path); ··· 7513 7511 7514 7512 if (prog->instances.nr == 1) { 7515 7513 /* don't create subdirs when pinning single instance */ 7516 - return bpf_program__unpin_instance(prog, path, 0); 7514 + return bpf_program_unpin_instance(prog, path, 0); 7517 7515 } 7518 7516 7519 7517 for (i = 0; i < prog->instances.nr; i++) { ··· 7526 7524 else if (len >= PATH_MAX) 7527 7525 return libbpf_err(-ENAMETOOLONG); 7528 7526 7529 - err = bpf_program__unpin_instance(prog, buf, i); 7527 + err = bpf_program_unpin_instance(prog, buf, i); 7530 7528 if (err) 7531 7529 return err; 7532 7530 } ··· 8143 8141 size_t bpf_program__size(const struct bpf_program *prog) 8144 8142 { 8145 8143 return prog->insns_cnt * BPF_INSN_SZ; 8144 + } 8145 + 8146 + const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog) 8147 + { 8148 + return prog->insns; 8149 + } 8150 + 8151 + size_t bpf_program__insn_cnt(const struct bpf_program *prog) 8152 + { 8153 + return prog->insns_cnt; 8146 8154 } 8147 8155 8148 8156 int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
+40 -3
tools/lib/bpf/libbpf.h
··· 224 224 LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload); 225 225 226 226 /* returns program size in bytes */ 227 + LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insn_cnt() instead") 227 228 LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog); 229 + 230 + struct bpf_insn; 231 + 232 + /** 233 + * @brief **bpf_program__insns()** gives read-only access to BPF program's 234 + * underlying BPF instructions. 235 + * @param prog BPF program for which to return instructions 236 + * @return a pointer to an array of BPF instructions that belong to the 237 + * specified BPF program 238 + * 239 + * Returned pointer is always valid and not NULL. Number of `struct bpf_insn` 240 + * pointed to can be fetched using **bpf_program__insn_cnt()** API. 241 + * 242 + * Keep in mind, libbpf can modify and append/delete BPF program's 243 + * instructions as it processes BPF object file and prepares everything for 244 + * uploading into the kernel. So depending on the point in BPF object 245 + * lifetime, **bpf_program__insns()** can return different sets of 246 + * instructions. As an example, during BPF object load phase BPF program 247 + * instructions will be CO-RE-relocated, BPF subprograms instructions will be 248 + * appended, ldimm64 instructions will have FDs embedded, etc. So instructions 249 + * returned before **bpf_object__load()** and after it might be quite 250 + * different. 251 + */ 252 + LIBBPF_API const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog); 253 + /** 254 + * @brief **bpf_program__insn_cnt()** returns number of `struct bpf_insn`'s 255 + * that form specified BPF program. 256 + * @param prog BPF program for which to return number of BPF instructions 257 + * 258 + * See **bpf_program__insns()** documentation for notes on how libbpf can 259 + * change instructions and their count during different phases of 260 + * **bpf_object** lifetime. 261 + */ 262 + LIBBPF_API size_t bpf_program__insn_cnt(const struct bpf_program *prog); 228 263 229 264 LIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license, 230 265 __u32 kern_version); 231 266 LIBBPF_API int bpf_program__fd(const struct bpf_program *prog); 267 + LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated") 232 268 LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog, 233 269 const char *path, 234 270 int instance); 271 + LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated") 235 272 LIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog, 236 273 const char *path, 237 274 int instance); ··· 402 365 bpf_program__attach_iter(const struct bpf_program *prog, 403 366 const struct bpf_iter_attach_opts *opts); 404 367 405 - struct bpf_insn; 406 - 407 368 /* 408 369 * Libbpf allows callers to adjust BPF programs before being loaded 409 370 * into kernel. One program in an object file can be transformed into ··· 430 395 * one instance. In this case bpf_program__fd(prog) is equal to 431 396 * bpf_program__nth_fd(prog, 0). 432 397 */ 433 - 398 + LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insns() for getting bpf_program instructions") 434 399 struct bpf_prog_prep_result { 435 400 /* 436 401 * If not NULL, load new instruction array. ··· 459 424 struct bpf_insn *insns, int insns_cnt, 460 425 struct bpf_prog_prep_result *res); 461 426 427 + LIBBPF_DEPRECATED_SINCE(0, 7, "use bpf_program__insns() for getting bpf_program instructions") 462 428 LIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, 463 429 bpf_program_prep_t prep); 464 430 431 + LIBBPF_DEPRECATED_SINCE(0, 7, "multi-instance bpf_program support is deprecated") 465 432 LIBBPF_API int bpf_program__nth_fd(const struct bpf_program *prog, int n); 466 433 467 434 /*
+2
tools/lib/bpf/libbpf.map
··· 393 393 bpf_object__next_program; 394 394 bpf_object__prev_map; 395 395 bpf_object__prev_program; 396 + bpf_program__insn_cnt; 397 + bpf_program__insns; 396 398 btf__add_btf; 397 399 btf__add_decl_tag; 398 400 btf__raw_data;