1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "bpf-foreign.h"
4 #include "bpf-program.h"
6 #include "memory-util.h"
7 #include "mountpoint-util.h"
10 typedef struct BPFForeignKey BPFForeignKey
;
11 struct BPFForeignKey
{
16 static int bpf_foreign_key_new(uint32_t prog_id
,
17 enum bpf_attach_type attach_type
,
18 BPFForeignKey
**ret
) {
19 _cleanup_free_ BPFForeignKey
*p
= NULL
;
23 p
= new(BPFForeignKey
, 1);
27 *p
= (BPFForeignKey
) {
29 .attach_type
= attach_type
,
37 static int bpf_foreign_key_compare_func(const BPFForeignKey
*a
, const BPFForeignKey
*b
) {
38 int r
= CMP(a
->prog_id
, b
->prog_id
);
42 return CMP(a
->attach_type
, b
->attach_type
);
45 static void bpf_foreign_key_hash_func(const BPFForeignKey
*p
, struct siphash
*h
) {
46 siphash24_compress(&p
->prog_id
, sizeof(p
->prog_id
), h
);
47 siphash24_compress(&p
->attach_type
, sizeof(p
->attach_type
), h
);
50 DEFINE_PRIVATE_HASH_OPS_FULL(bpf_foreign_by_key_hash_ops
,
51 BPFForeignKey
, bpf_foreign_key_hash_func
, bpf_foreign_key_compare_func
, free
,
52 BPFProgram
, bpf_program_unref
);
54 static int attach_programs(Unit
*u
, const char *path
, Hashmap
* foreign_by_key
, uint32_t attach_flags
) {
55 const BPFForeignKey
*key
;
61 HASHMAP_FOREACH_KEY(prog
, key
, foreign_by_key
) {
62 r
= bpf_program_cgroup_attach(prog
, key
->attach_type
, path
, attach_flags
);
64 return log_unit_error_errno(u
, r
, "Attaching foreign BPF program to cgroup %s failed: %m", path
);
71 * Prepare foreign BPF program for installation:
72 * - Load the program from BPF filesystem to the kernel;
73 * - Store program FD identified by program ID and attach type in the unit.
75 static int bpf_foreign_prepare(
77 enum bpf_attach_type attach_type
,
78 const char *bpffs_path
) {
79 _cleanup_(bpf_program_unrefp
) BPFProgram
*prog
= NULL
;
80 _cleanup_free_ BPFForeignKey
*key
= NULL
;
87 r
= bpf_program_new_from_bpffs_path(bpffs_path
, &prog
);
89 return log_unit_error_errno(u
, r
, "Failed to create foreign BPFProgram: %m");
91 r
= bpf_program_get_id_by_fd(prog
->kernel_fd
, &prog_id
);
93 return log_unit_error_errno(u
, r
, "Failed to get BPF program id by fd: %m");
95 r
= bpf_foreign_key_new(prog_id
, attach_type
, &key
);
97 return log_unit_error_errno(u
, r
,
98 "Failed to create foreign BPF program key from path '%s': %m", bpffs_path
);
100 r
= hashmap_ensure_put(&u
->bpf_foreign_by_key
, &bpf_foreign_by_key_hash_ops
, key
, prog
);
102 log_unit_warning_errno(u
, r
, "Foreign BPF program already exists, ignoring: %m");
106 return log_unit_error_errno(u
, r
, "Failed to put foreign BPFProgram into map: %m");
114 int bpf_foreign_supported(void) {
117 r
= cg_all_unified();
121 return path_is_mount_point("/sys/fs/bpf", NULL
, 0);
124 int bpf_foreign_install(Unit
*u
) {
125 _cleanup_free_
char *cgroup_path
= NULL
;
126 CGroupBPFForeignProgram
*p
;
132 cc
= unit_get_cgroup_context(u
);
136 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
138 return log_unit_error_errno(u
, r
, "Failed to get cgroup path: %m");
140 LIST_FOREACH(programs
, p
, cc
->bpf_foreign_programs
) {
141 r
= bpf_foreign_prepare(u
, p
->attach_type
, p
->bpffs_path
);
143 return log_unit_error_errno(u
, r
, "Failed to prepare foreign BPF hashmap: %m");
146 r
= attach_programs(u
, cgroup_path
, u
->bpf_foreign_by_key
, BPF_F_ALLOW_MULTI
);
148 return log_unit_error_errno(u
, r
, "Failed to install foreign BPF programs: %m");