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

libbpf: Support exclusive map creation

Implement setters and getters that allow map to be registered as
exclusive to the specified program. The registration should be done
before the exclusive program is loaded.

Signed-off-by: KP Singh <kpsingh@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20250914215141.15144-5-kpsingh@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

KP Singh and committed by
Alexei Starovoitov
567010a5 c297fe3e

+101 -2
+3 -1
tools/lib/bpf/bpf.c
··· 172 172 __u32 max_entries, 173 173 const struct bpf_map_create_opts *opts) 174 174 { 175 - const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd); 175 + const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash_size); 176 176 union bpf_attr attr; 177 177 int fd; 178 178 ··· 203 203 attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0); 204 204 205 205 attr.map_token_fd = OPTS_GET(opts, token_fd, 0); 206 + attr.excl_prog_hash = ptr_to_u64(OPTS_GET(opts, excl_prog_hash, NULL)); 207 + attr.excl_prog_hash_size = OPTS_GET(opts, excl_prog_hash_size, 0); 206 208 207 209 fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz); 208 210 return libbpf_err_errno(fd);
+4 -1
tools/lib/bpf/bpf.h
··· 54 54 __s32 value_type_btf_obj_fd; 55 55 56 56 __u32 token_fd; 57 + 58 + const void *excl_prog_hash; 59 + __u32 excl_prog_hash_size; 57 60 size_t :0; 58 61 }; 59 - #define bpf_map_create_opts__last_field token_fd 62 + #define bpf_map_create_opts__last_field excl_prog_hash_size 60 63 61 64 LIBBPF_API int bpf_map_create(enum bpf_map_type map_type, 62 65 const char *map_name,
+69
tools/lib/bpf/libbpf.c
··· 499 499 __u32 line_info_rec_size; 500 500 __u32 line_info_cnt; 501 501 __u32 prog_flags; 502 + __u8 hash[SHA256_DIGEST_LENGTH]; 502 503 }; 503 504 504 505 struct bpf_struct_ops { ··· 579 578 bool autocreate; 580 579 bool autoattach; 581 580 __u64 map_extra; 581 + struct bpf_program *excl_prog; 582 582 }; 583 583 584 584 enum extern_type { ··· 4490 4488 } 4491 4489 } 4492 4490 4491 + static int bpf_prog_compute_hash(struct bpf_program *prog) 4492 + { 4493 + struct bpf_insn *purged; 4494 + int i, err; 4495 + 4496 + purged = calloc(prog->insns_cnt, BPF_INSN_SZ); 4497 + if (!purged) 4498 + return -ENOMEM; 4499 + 4500 + /* If relocations have been done, the map_fd needs to be 4501 + * discarded for the digest calculation. 4502 + */ 4503 + for (i = 0; i < prog->insns_cnt; i++) { 4504 + purged[i] = prog->insns[i]; 4505 + if (purged[i].code == (BPF_LD | BPF_IMM | BPF_DW) && 4506 + (purged[i].src_reg == BPF_PSEUDO_MAP_FD || 4507 + purged[i].src_reg == BPF_PSEUDO_MAP_VALUE)) { 4508 + purged[i].imm = 0; 4509 + i++; 4510 + if (i >= prog->insns_cnt || 4511 + prog->insns[i].code != 0 || 4512 + prog->insns[i].dst_reg != 0 || 4513 + prog->insns[i].src_reg != 0 || 4514 + prog->insns[i].off != 0) { 4515 + err = -EINVAL; 4516 + goto out; 4517 + } 4518 + purged[i] = prog->insns[i]; 4519 + purged[i].imm = 0; 4520 + } 4521 + } 4522 + err = libbpf_sha256(purged, prog->insns_cnt * sizeof(struct bpf_insn), 4523 + prog->hash, SHA256_DIGEST_LENGTH); 4524 + out: 4525 + free(purged); 4526 + return err; 4527 + } 4528 + 4493 4529 static int bpf_program__record_reloc(struct bpf_program *prog, 4494 4530 struct reloc_desc *reloc_desc, 4495 4531 __u32 insn_idx, const char *sym_name, ··· 5277 5237 create_attr.token_fd = obj->token_fd; 5278 5238 if (obj->token_fd) 5279 5239 create_attr.map_flags |= BPF_F_TOKEN_FD; 5240 + if (map->excl_prog) { 5241 + err = bpf_prog_compute_hash(map->excl_prog); 5242 + if (err) 5243 + return err; 5244 + 5245 + create_attr.excl_prog_hash = map->excl_prog->hash; 5246 + create_attr.excl_prog_hash_size = SHA256_DIGEST_LENGTH; 5247 + } 5280 5248 5281 5249 if (bpf_map__is_struct_ops(map)) { 5282 5250 create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; ··· 10573 10525 } 10574 10526 map->inner_map_fd = fd; 10575 10527 return 0; 10528 + } 10529 + 10530 + int bpf_map__set_exclusive_program(struct bpf_map *map, struct bpf_program *prog) 10531 + { 10532 + if (map_is_created(map)) { 10533 + pr_warn("exclusive programs must be set before map creation\n"); 10534 + return libbpf_err(-EINVAL); 10535 + } 10536 + 10537 + if (map->obj != prog->obj) { 10538 + pr_warn("excl_prog and map must be from the same bpf object\n"); 10539 + return libbpf_err(-EINVAL); 10540 + } 10541 + 10542 + map->excl_prog = prog; 10543 + return 0; 10544 + } 10545 + 10546 + struct bpf_program *bpf_map__exclusive_program(struct bpf_map *map) 10547 + { 10548 + return map->excl_prog; 10576 10549 } 10577 10550 10578 10551 static struct bpf_map *
+22
tools/lib/bpf/libbpf.h
··· 1291 1291 */ 1292 1292 LIBBPF_API int bpf_map__get_next_key(const struct bpf_map *map, 1293 1293 const void *cur_key, void *next_key, size_t key_sz); 1294 + /** 1295 + * @brief **bpf_map__set_exclusive_program()** sets a map to be exclusive to the 1296 + * specified program. This must be called *before* the map is created. 1297 + * 1298 + * @param map BPF map to make exclusive. 1299 + * @param prog BPF program to be the exclusive user of the map. Must belong 1300 + * to the same bpf_object as the map. 1301 + * @return 0 on success; a negative error code otherwise. 1302 + * 1303 + * This function must be called after the BPF object is opened but before 1304 + * it is loaded. Once the object is loaded, only the specified program 1305 + * will be able to access the map's contents. 1306 + */ 1307 + LIBBPF_API int bpf_map__set_exclusive_program(struct bpf_map *map, struct bpf_program *prog); 1308 + 1309 + /** 1310 + * @brief **bpf_map__exclusive_program()** returns the exclusive program 1311 + * that is registered with the map (if any). 1312 + * @param map BPF map to which the exclusive program is registered. 1313 + * @return the registered exclusive program. 1314 + */ 1315 + LIBBPF_API struct bpf_program *bpf_map__exclusive_program(struct bpf_map *map); 1294 1316 1295 1317 struct bpf_xdp_set_link_opts { 1296 1318 size_t sz;
+3
tools/lib/bpf/libbpf.map
··· 448 448 } LIBBPF_1.5.0; 449 449 450 450 LIBBPF_1.7.0 { 451 + global: 452 + bpf_map__set_exclusive_program; 453 + bpf_map__exclusive_program; 451 454 } LIBBPF_1.6.0;