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 log_unit_error_errno(u
, r
, "bpf-foreign: Attaching foreign BPF program to cgroup %s failed: %m", path
);
76 * Prepare foreign BPF program for installation:
77 * - Load the program from BPF filesystem to the kernel;
78 * - Store program FD identified by program ID and attach type in the unit.
80 static int bpf_foreign_prepare(
82 enum bpf_attach_type attach_type
,
83 const char *bpffs_path
) {
84 _cleanup_(bpf_program_freep
) BPFProgram
*prog
= NULL
;
85 _cleanup_free_ BPFForeignKey
*key
= NULL
;
92 r
= path_is_fs_type(bpffs_path
, BPF_FS_MAGIC
);
94 log_unit_warning_errno(u
, r
, "bpf-foreign: foreign program %s does not exist, skipping.", bpffs_path
);
98 return log_unit_error_errno(u
, r
,
99 "bpf-foreign: Failed to determine filesystem type of %s: %m", bpffs_path
);
101 return log_unit_error_errno(u
, SYNTHETIC_ERRNO(EINVAL
),
102 "bpf-foreign: Path in BPF filesystem is expected.");
104 r
= bpf_program_new_from_bpffs_path(bpffs_path
, &prog
);
106 return log_unit_error_errno(u
, r
, "bpf-foreign: Failed to create foreign BPF program: %m");
108 r
= bpf_program_get_id_by_fd(prog
->kernel_fd
, &prog_id
);
110 return log_unit_error_errno(u
, r
, "bpf-foreign: Failed to get BPF program id from fd: %m");
112 r
= bpf_foreign_key_new(prog_id
, attach_type
, &key
);
114 return log_unit_error_errno(u
, r
,
115 "bpf-foreign: Failed to create foreign BPF program key from path '%s': %m", bpffs_path
);
117 r
= hashmap_ensure_put(&u
->bpf_foreign_by_key
, &bpf_foreign_by_key_hash_ops
, key
, prog
);
119 log_unit_warning_errno(u
, r
, "bpf-foreign: Foreign BPF program already exists, ignoring: %m");
123 return log_unit_error_errno(u
, r
, "bpf-foreign: Failed to put foreign BPF program into map: %m");
131 int bpf_foreign_install(Unit
*u
) {
132 _cleanup_free_
char *cgroup_path
= NULL
;
138 cc
= unit_get_cgroup_context(u
);
142 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
144 return log_unit_error_errno(u
, r
, "bpf-foreign: Failed to get cgroup path: %m");
146 LIST_FOREACH(programs
, p
, cc
->bpf_foreign_programs
) {
147 r
= bpf_foreign_prepare(u
, p
->attach_type
, p
->bpffs_path
);
148 if (r
< 0 && ret
>= 0)
152 r
= attach_programs(u
, cgroup_path
, u
->bpf_foreign_by_key
, BPF_F_ALLOW_MULTI
);
153 return ret
< 0 ? ret
: r
;