1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "bpf-foreign.h"
4 #include "bpf-program.h"
6 #include "memory-util.h"
7 #include "missing_magic.h"
8 #include "mountpoint-util.h"
10 #include "stat-util.h"
12 typedef struct BPFForeignKey BPFForeignKey
;
13 struct BPFForeignKey
{
18 static int bpf_foreign_key_new(uint32_t prog_id
,
19 enum bpf_attach_type attach_type
,
20 BPFForeignKey
**ret
) {
21 _cleanup_free_ BPFForeignKey
*p
= NULL
;
25 p
= new(BPFForeignKey
, 1);
29 *p
= (BPFForeignKey
) {
31 .attach_type
= attach_type
,
39 static int bpf_foreign_key_compare_func(const BPFForeignKey
*a
, const BPFForeignKey
*b
) {
40 int r
= CMP(a
->prog_id
, b
->prog_id
);
44 return CMP(a
->attach_type
, b
->attach_type
);
47 static void bpf_foreign_key_hash_func(const BPFForeignKey
*p
, struct siphash
*h
) {
48 siphash24_compress(&p
->prog_id
, sizeof(p
->prog_id
), h
);
49 siphash24_compress(&p
->attach_type
, sizeof(p
->attach_type
), h
);
52 DEFINE_PRIVATE_HASH_OPS_FULL(bpf_foreign_by_key_hash_ops
,
53 BPFForeignKey
, bpf_foreign_key_hash_func
, bpf_foreign_key_compare_func
, free
,
54 BPFProgram
, bpf_program_free
);
56 static int attach_programs(Unit
*u
, const char *path
, Hashmap
* foreign_by_key
, uint32_t attach_flags
) {
57 const BPFForeignKey
*key
;
63 HASHMAP_FOREACH_KEY(prog
, key
, foreign_by_key
) {
64 r
= bpf_program_cgroup_attach(prog
, key
->attach_type
, path
, attach_flags
);
66 return log_unit_error_errno(u
, r
, "Attaching foreign BPF program to cgroup %s failed: %m", path
);
73 * Prepare foreign BPF program for installation:
74 * - Load the program from BPF filesystem to the kernel;
75 * - Store program FD identified by program ID and attach type in the unit.
77 static int bpf_foreign_prepare(
79 enum bpf_attach_type attach_type
,
80 const char *bpffs_path
) {
81 _cleanup_(bpf_program_freep
) BPFProgram
*prog
= NULL
;
82 _cleanup_free_ BPFForeignKey
*key
= NULL
;
89 r
= path_is_fs_type(bpffs_path
, BPF_FS_MAGIC
);
91 return log_unit_error_errno(u
, r
,
92 "Failed to determine filesystem type of %s: %m", bpffs_path
);
94 return log_unit_error_errno(u
, SYNTHETIC_ERRNO(EINVAL
),
95 "Path in BPF filesystem is expected.");
97 r
= bpf_program_new_from_bpffs_path(bpffs_path
, &prog
);
99 return log_unit_error_errno(u
, r
, "Failed to create foreign BPFProgram: %m");
101 r
= bpf_program_get_id_by_fd(prog
->kernel_fd
, &prog_id
);
103 return log_unit_error_errno(u
, r
, "Failed to get BPF program id by fd: %m");
105 r
= bpf_foreign_key_new(prog_id
, attach_type
, &key
);
107 return log_unit_error_errno(u
, r
,
108 "Failed to create foreign BPF program key from path '%s': %m", bpffs_path
);
110 r
= hashmap_ensure_put(&u
->bpf_foreign_by_key
, &bpf_foreign_by_key_hash_ops
, key
, prog
);
112 log_unit_warning_errno(u
, r
, "Foreign BPF program already exists, ignoring: %m");
116 return log_unit_error_errno(u
, r
, "Failed to put foreign BPFProgram into map: %m");
124 int bpf_foreign_install(Unit
*u
) {
125 _cleanup_free_
char *cgroup_path
= NULL
;
131 cc
= unit_get_cgroup_context(u
);
135 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
137 return log_unit_error_errno(u
, r
, "Failed to get cgroup path: %m");
139 LIST_FOREACH(programs
, p
, cc
->bpf_foreign_programs
) {
140 r
= bpf_foreign_prepare(u
, p
->attach_type
, p
->bpffs_path
);
142 return log_unit_error_errno(u
, r
, "Failed to prepare foreign BPF hashmap: %m");
145 r
= attach_programs(u
, cgroup_path
, u
->bpf_foreign_by_key
, BPF_F_ALLOW_MULTI
);
147 return log_unit_error_errno(u
, r
, "Failed to install foreign BPF programs: %m");