2021-09-29 18:16:09 +01:00
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2020-09-16 15:58:04 -07:00
# include "bpf-foreign.h"
# include "bpf-program.h"
# include "cgroup.h"
# include "memory-util.h"
2021-11-04 18:55:55 -07:00
# include "missing_magic.h"
2020-09-16 15:58:04 -07:00
# include "mountpoint-util.h"
# include "set.h"
2021-11-04 18:55:55 -07:00
# include "stat-util.h"
2020-09-16 15:58:04 -07:00
typedef struct BPFForeignKey BPFForeignKey ;
struct BPFForeignKey {
uint32_t prog_id ;
uint32_t attach_type ;
} ;
static int bpf_foreign_key_new ( uint32_t prog_id ,
enum bpf_attach_type attach_type ,
BPFForeignKey * * ret ) {
_cleanup_free_ BPFForeignKey * p = NULL ;
assert ( ret ) ;
p = new ( BPFForeignKey , 1 ) ;
if ( ! p )
return log_oom ( ) ;
* p = ( BPFForeignKey ) {
. prog_id = prog_id ,
. attach_type = attach_type ,
} ;
* ret = TAKE_PTR ( p ) ;
return 0 ;
}
static int bpf_foreign_key_compare_func ( const BPFForeignKey * a , const BPFForeignKey * b ) {
int r = CMP ( a - > prog_id , b - > prog_id ) ;
if ( r ! = 0 )
return r ;
return CMP ( a - > attach_type , b - > attach_type ) ;
}
static void bpf_foreign_key_hash_func ( const BPFForeignKey * p , struct siphash * h ) {
siphash24_compress ( & p - > prog_id , sizeof ( p - > prog_id ) , h ) ;
siphash24_compress ( & p - > attach_type , sizeof ( p - > attach_type ) , h ) ;
}
DEFINE_PRIVATE_HASH_OPS_FULL ( bpf_foreign_by_key_hash_ops ,
BPFForeignKey , bpf_foreign_key_hash_func , bpf_foreign_key_compare_func , free ,
2021-08-18 16:01:05 -07:00
BPFProgram , bpf_program_free ) ;
2020-09-16 15:58:04 -07:00
static int attach_programs ( Unit * u , const char * path , Hashmap * foreign_by_key , uint32_t attach_flags ) {
const BPFForeignKey * key ;
BPFProgram * prog ;
int r ;
assert ( u ) ;
HASHMAP_FOREACH_KEY ( prog , key , foreign_by_key ) {
r = bpf_program_cgroup_attach ( prog , key - > attach_type , path , attach_flags ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Attaching foreign BPF program to cgroup %s failed: %m " , path ) ;
}
return 0 ;
}
/*
* Prepare foreign BPF program for installation :
* - Load the program from BPF filesystem to the kernel ;
* - Store program FD identified by program ID and attach type in the unit .
*/
static int bpf_foreign_prepare (
Unit * u ,
enum bpf_attach_type attach_type ,
const char * bpffs_path ) {
2021-08-18 16:01:05 -07:00
_cleanup_ ( bpf_program_freep ) BPFProgram * prog = NULL ;
2020-09-16 15:58:04 -07:00
_cleanup_free_ BPFForeignKey * key = NULL ;
uint32_t prog_id ;
int r ;
assert ( u ) ;
assert ( bpffs_path ) ;
2021-11-04 18:55:55 -07:00
r = path_is_fs_type ( bpffs_path , BPF_FS_MAGIC ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r ,
" Failed to determine filesystem type of %s: %m " , bpffs_path ) ;
if ( r = = 0 )
return log_unit_error_errno ( u , SYNTHETIC_ERRNO ( EINVAL ) ,
" Path in BPF filesystem is expected. " ) ;
2020-09-16 15:58:04 -07:00
r = bpf_program_new_from_bpffs_path ( bpffs_path , & prog ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to create foreign BPFProgram: %m " ) ;
r = bpf_program_get_id_by_fd ( prog - > kernel_fd , & prog_id ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to get BPF program id by fd: %m " ) ;
r = bpf_foreign_key_new ( prog_id , attach_type , & key ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r ,
" Failed to create foreign BPF program key from path '%s': %m " , bpffs_path ) ;
r = hashmap_ensure_put ( & u - > bpf_foreign_by_key , & bpf_foreign_by_key_hash_ops , key , prog ) ;
if ( r = = - EEXIST ) {
log_unit_warning_errno ( u , r , " Foreign BPF program already exists, ignoring: %m " ) ;
return 0 ;
}
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to put foreign BPFProgram into map: %m " ) ;
TAKE_PTR ( key ) ;
TAKE_PTR ( prog ) ;
return 0 ;
}
int bpf_foreign_install ( Unit * u ) {
_cleanup_free_ char * cgroup_path = NULL ;
CGroupBPFForeignProgram * p ;
CGroupContext * cc ;
int r ;
assert ( u ) ;
cc = unit_get_cgroup_context ( u ) ;
if ( ! cc )
return 0 ;
r = cg_get_path ( SYSTEMD_CGROUP_CONTROLLER , u - > cgroup_path , NULL , & cgroup_path ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to get cgroup path: %m " ) ;
LIST_FOREACH ( programs , p , cc - > bpf_foreign_programs ) {
r = bpf_foreign_prepare ( u , p - > attach_type , p - > bpffs_path ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to prepare foreign BPF hashmap: %m " ) ;
}
r = attach_programs ( u , cgroup_path , u - > bpf_foreign_by_key , BPF_F_ALLOW_MULTI ) ;
if ( r < 0 )
return log_unit_error_errno ( u , r , " Failed to install foreign BPF programs: %m " ) ;
return 0 ;
}