2019-12-18 23:44:37 -08:00
// SPDX-License-Identifier: GPL-2.0
# include <test_progs.h>
# include "cgroup_helpers.h"
# define PING_CMD "ping -q -c1 -w1 127.0.0.1 > / dev / null"
2020-03-02 15:53:48 +01:00
static char bpf_log_buf [ BPF_LOG_BUF_SIZE ] ;
2019-12-18 23:44:37 -08:00
static int map_fd = - 1 ;
static int prog_load_cnt ( int verdict , int val )
{
int cgroup_storage_fd , percpu_cgroup_storage_fd ;
if ( map_fd < 0 )
2021-11-24 11:32:33 -08:00
map_fd = bpf_map_create ( BPF_MAP_TYPE_ARRAY , NULL , 4 , 8 , 1 , NULL ) ;
2019-12-18 23:44:37 -08:00
if ( map_fd < 0 ) {
printf ( " failed to create map '%s' \n " , strerror ( errno ) ) ;
return - 1 ;
}
2021-11-24 11:32:33 -08:00
cgroup_storage_fd = bpf_map_create ( BPF_MAP_TYPE_CGROUP_STORAGE , NULL ,
sizeof ( struct bpf_cgroup_storage_key ) , 8 , 0 , NULL ) ;
2019-12-18 23:44:37 -08:00
if ( cgroup_storage_fd < 0 ) {
printf ( " failed to create map '%s' \n " , strerror ( errno ) ) ;
return - 1 ;
}
2021-11-24 11:32:33 -08:00
percpu_cgroup_storage_fd = bpf_map_create (
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE , NULL ,
sizeof ( struct bpf_cgroup_storage_key ) , 8 , 0 , NULL ) ;
2019-12-18 23:44:37 -08:00
if ( percpu_cgroup_storage_fd < 0 ) {
printf ( " failed to create map '%s' \n " , strerror ( errno ) ) ;
return - 1 ;
}
struct bpf_insn prog [ ] = {
BPF_MOV32_IMM ( BPF_REG_0 , 0 ) ,
BPF_STX_MEM ( BPF_W , BPF_REG_10 , BPF_REG_0 , - 4 ) , /* *(u32 *)(fp - 4) = r0 */
BPF_MOV64_REG ( BPF_REG_2 , BPF_REG_10 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_2 , - 4 ) , /* r2 = fp - 4 */
BPF_LD_MAP_FD ( BPF_REG_1 , map_fd ) ,
BPF_RAW_INSN ( BPF_JMP | BPF_CALL , 0 , 0 , 0 , BPF_FUNC_map_lookup_elem ) ,
BPF_JMP_IMM ( BPF_JEQ , BPF_REG_0 , 0 , 2 ) ,
BPF_MOV64_IMM ( BPF_REG_1 , val ) , /* r1 = 1 */
2021-01-14 18:17:44 +00:00
BPF_ATOMIC_OP ( BPF_DW , BPF_ADD , BPF_REG_0 , BPF_REG_1 , 0 ) ,
2019-12-18 23:44:37 -08:00
BPF_LD_MAP_FD ( BPF_REG_1 , cgroup_storage_fd ) ,
BPF_MOV64_IMM ( BPF_REG_2 , 0 ) ,
BPF_RAW_INSN ( BPF_JMP | BPF_CALL , 0 , 0 , 0 , BPF_FUNC_get_local_storage ) ,
BPF_MOV64_IMM ( BPF_REG_1 , val ) ,
2021-01-14 18:17:44 +00:00
BPF_ATOMIC_OP ( BPF_W , BPF_ADD , BPF_REG_0 , BPF_REG_1 , 0 ) ,
2019-12-18 23:44:37 -08:00
BPF_LD_MAP_FD ( BPF_REG_1 , percpu_cgroup_storage_fd ) ,
BPF_MOV64_IMM ( BPF_REG_2 , 0 ) ,
BPF_RAW_INSN ( BPF_JMP | BPF_CALL , 0 , 0 , 0 , BPF_FUNC_get_local_storage ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_3 , BPF_REG_0 , 0 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_3 , 0x1 ) ,
BPF_STX_MEM ( BPF_W , BPF_REG_0 , BPF_REG_3 , 0 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , verdict ) , /* r0 = verdict */
BPF_EXIT_INSN ( ) ,
} ;
size_t insns_cnt = sizeof ( prog ) / sizeof ( struct bpf_insn ) ;
int ret ;
2021-11-03 15:08:45 -07:00
ret = bpf_test_load_program ( BPF_PROG_TYPE_CGROUP_SKB ,
2019-12-18 23:44:37 -08:00
prog , insns_cnt , " GPL " , 0 ,
bpf_log_buf , BPF_LOG_BUF_SIZE ) ;
close ( cgroup_storage_fd ) ;
return ret ;
}
2021-10-06 11:56:19 -07:00
void serial_test_cgroup_attach_multi ( void )
2019-12-18 23:44:37 -08:00
{
__u32 prog_ids [ 4 ] , prog_cnt = 0 , attach_flags , saved_prog_id ;
int cg1 = 0 , cg2 = 0 , cg3 = 0 , cg4 = 0 , cg5 = 0 , key = 0 ;
2019-12-18 23:44:38 -08:00
DECLARE_LIBBPF_OPTS ( bpf_prog_attach_opts , attach_opts ) ;
int allow_prog [ 7 ] = { - 1 } ;
2019-12-18 23:44:37 -08:00
unsigned long long value ;
__u32 duration = 0 ;
int i = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( allow_prog ) ; i + + ) {
allow_prog [ i ] = prog_load_cnt ( 1 , 1 < < i ) ;
if ( CHECK ( allow_prog [ i ] < 0 , " prog_load " ,
" verifier output: \n %s \n ------- \n " , bpf_log_buf ) )
goto err ;
}
if ( CHECK_FAIL ( setup_cgroup_environment ( ) ) )
goto err ;
cg1 = create_and_get_cgroup ( " /cg1 " ) ;
if ( CHECK_FAIL ( cg1 < 0 ) )
goto err ;
cg2 = create_and_get_cgroup ( " /cg1/cg2 " ) ;
if ( CHECK_FAIL ( cg2 < 0 ) )
goto err ;
cg3 = create_and_get_cgroup ( " /cg1/cg2/cg3 " ) ;
if ( CHECK_FAIL ( cg3 < 0 ) )
goto err ;
cg4 = create_and_get_cgroup ( " /cg1/cg2/cg3/cg4 " ) ;
if ( CHECK_FAIL ( cg4 < 0 ) )
goto err ;
cg5 = create_and_get_cgroup ( " /cg1/cg2/cg3/cg4/cg5 " ) ;
if ( CHECK_FAIL ( cg5 < 0 ) )
goto err ;
if ( CHECK_FAIL ( join_cgroup ( " /cg1/cg2/cg3/cg4/cg5 " ) ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 0 ] , cg1 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_MULTI ) ,
" prog0_attach_to_cg1_multi " , " errno=%d \n " , errno ) )
goto err ;
if ( CHECK ( ! bpf_prog_attach ( allow_prog [ 0 ] , cg1 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_MULTI ) ,
" fail_same_prog_attach_to_cg1 " , " unexpected success \n " ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 1 ] , cg1 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_MULTI ) ,
" prog1_attach_to_cg1_multi " , " errno=%d \n " , errno ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 2 ] , cg2 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_OVERRIDE ) ,
" prog2_attach_to_cg2_override " , " errno=%d \n " , errno ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 3 ] , cg3 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_MULTI ) ,
" prog3_attach_to_cg3_multi " , " errno=%d \n " , errno ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 4 ] , cg4 , BPF_CGROUP_INET_EGRESS ,
BPF_F_ALLOW_OVERRIDE ) ,
" prog4_attach_to_cg4_override " , " errno=%d \n " , errno ) )
goto err ;
if ( CHECK ( bpf_prog_attach ( allow_prog [ 5 ] , cg5 , BPF_CGROUP_INET_EGRESS , 0 ) ,
" prog5_attach_to_cg5_none " , " errno=%d \n " , errno ) )
goto err ;
CHECK_FAIL ( system ( PING_CMD ) ) ;
CHECK_FAIL ( bpf_map_lookup_elem ( map_fd , & key , & value ) ) ;
CHECK_FAIL ( value ! = 1 + 2 + 8 + 32 ) ;
/* query the number of effective progs in cg5 */
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS ,
BPF_F_QUERY_EFFECTIVE , NULL , NULL , & prog_cnt ) ) ;
CHECK_FAIL ( prog_cnt ! = 4 ) ;
/* retrieve prog_ids of effective progs in cg5 */
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS ,
BPF_F_QUERY_EFFECTIVE , & attach_flags ,
prog_ids , & prog_cnt ) ) ;
CHECK_FAIL ( prog_cnt ! = 4 ) ;
CHECK_FAIL ( attach_flags ! = 0 ) ;
saved_prog_id = prog_ids [ 0 ] ;
/* check enospc handling */
prog_ids [ 0 ] = 0 ;
prog_cnt = 2 ;
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS ,
BPF_F_QUERY_EFFECTIVE , & attach_flags ,
2021-05-24 20:59:32 -07:00
prog_ids , & prog_cnt ) > = 0 ) ;
2019-12-18 23:44:37 -08:00
CHECK_FAIL ( errno ! = ENOSPC ) ;
CHECK_FAIL ( prog_cnt ! = 4 ) ;
/* check that prog_ids are returned even when buffer is too small */
CHECK_FAIL ( prog_ids [ 0 ] ! = saved_prog_id ) ;
/* retrieve prog_id of single attached prog in cg5 */
prog_ids [ 0 ] = 0 ;
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS , 0 , NULL ,
prog_ids , & prog_cnt ) ) ;
CHECK_FAIL ( prog_cnt ! = 1 ) ;
CHECK_FAIL ( prog_ids [ 0 ] ! = saved_prog_id ) ;
/* detach bottom program and ping again */
if ( CHECK ( bpf_prog_detach2 ( - 1 , cg5 , BPF_CGROUP_INET_EGRESS ) ,
" prog_detach_from_cg5 " , " errno=%d \n " , errno ) )
goto err ;
value = 0 ;
CHECK_FAIL ( bpf_map_update_elem ( map_fd , & key , & value , 0 ) ) ;
CHECK_FAIL ( system ( PING_CMD ) ) ;
CHECK_FAIL ( bpf_map_lookup_elem ( map_fd , & key , & value ) ) ;
CHECK_FAIL ( value ! = 1 + 2 + 8 + 16 ) ;
2019-12-18 23:44:38 -08:00
/* test replace */
attach_opts . flags = BPF_F_ALLOW_OVERRIDE | BPF_F_REPLACE ;
attach_opts . replace_prog_fd = allow_prog [ 0 ] ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( ! bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2019-12-18 23:44:38 -08:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" fail_prog_replace_override " , " unexpected success \n " ) )
goto err ;
CHECK_FAIL ( errno ! = EINVAL ) ;
attach_opts . flags = BPF_F_REPLACE ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( ! bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2019-12-18 23:44:38 -08:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" fail_prog_replace_no_multi " , " unexpected success \n " ) )
goto err ;
CHECK_FAIL ( errno ! = EINVAL ) ;
attach_opts . flags = BPF_F_ALLOW_MULTI | BPF_F_REPLACE ;
attach_opts . replace_prog_fd = - 1 ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( ! bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2019-12-18 23:44:38 -08:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" fail_prog_replace_bad_fd " , " unexpected success \n " ) )
goto err ;
CHECK_FAIL ( errno ! = EBADF ) ;
/* replacing a program that is not attached to cgroup should fail */
attach_opts . replace_prog_fd = allow_prog [ 3 ] ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( ! bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2019-12-18 23:44:38 -08:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" fail_prog_replace_no_ent " , " unexpected success \n " ) )
goto err ;
CHECK_FAIL ( errno ! = ENOENT ) ;
/* replace 1st from the top program */
attach_opts . replace_prog_fd = allow_prog [ 0 ] ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2019-12-18 23:44:38 -08:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" prog_replace " , " errno=%d \n " , errno ) )
goto err ;
2020-06-08 17:22:01 +01:00
/* replace program with itself */
attach_opts . replace_prog_fd = allow_prog [ 6 ] ;
2022-01-07 10:46:04 -08:00
if ( CHECK ( bpf_prog_attach_opts ( allow_prog [ 6 ] , cg1 ,
2020-06-08 17:22:01 +01:00
BPF_CGROUP_INET_EGRESS , & attach_opts ) ,
" prog_replace " , " errno=%d \n " , errno ) )
goto err ;
2019-12-18 23:44:38 -08:00
value = 0 ;
CHECK_FAIL ( bpf_map_update_elem ( map_fd , & key , & value , 0 ) ) ;
CHECK_FAIL ( system ( PING_CMD ) ) ;
CHECK_FAIL ( bpf_map_lookup_elem ( map_fd , & key , & value ) ) ;
CHECK_FAIL ( value ! = 64 + 2 + 8 + 16 ) ;
2019-12-18 23:44:37 -08:00
/* detach 3rd from bottom program and ping again */
if ( CHECK ( ! bpf_prog_detach2 ( 0 , cg3 , BPF_CGROUP_INET_EGRESS ) ,
" fail_prog_detach_from_cg3 " , " unexpected success \n " ) )
goto err ;
if ( CHECK ( bpf_prog_detach2 ( allow_prog [ 3 ] , cg3 , BPF_CGROUP_INET_EGRESS ) ,
" prog3_detach_from_cg3 " , " errno=%d \n " , errno ) )
goto err ;
value = 0 ;
CHECK_FAIL ( bpf_map_update_elem ( map_fd , & key , & value , 0 ) ) ;
CHECK_FAIL ( system ( PING_CMD ) ) ;
CHECK_FAIL ( bpf_map_lookup_elem ( map_fd , & key , & value ) ) ;
2019-12-18 23:44:38 -08:00
CHECK_FAIL ( value ! = 64 + 2 + 16 ) ;
2019-12-18 23:44:37 -08:00
/* detach 2nd from bottom program and ping again */
if ( CHECK ( bpf_prog_detach2 ( - 1 , cg4 , BPF_CGROUP_INET_EGRESS ) ,
" prog_detach_from_cg4 " , " errno=%d \n " , errno ) )
goto err ;
value = 0 ;
CHECK_FAIL ( bpf_map_update_elem ( map_fd , & key , & value , 0 ) ) ;
CHECK_FAIL ( system ( PING_CMD ) ) ;
CHECK_FAIL ( bpf_map_lookup_elem ( map_fd , & key , & value ) ) ;
2019-12-18 23:44:38 -08:00
CHECK_FAIL ( value ! = 64 + 2 + 4 ) ;
2019-12-18 23:44:37 -08:00
prog_cnt = 4 ;
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS ,
BPF_F_QUERY_EFFECTIVE , & attach_flags ,
prog_ids , & prog_cnt ) ) ;
CHECK_FAIL ( prog_cnt ! = 3 ) ;
CHECK_FAIL ( attach_flags ! = 0 ) ;
CHECK_FAIL ( bpf_prog_query ( cg5 , BPF_CGROUP_INET_EGRESS , 0 , NULL ,
prog_ids , & prog_cnt ) ) ;
CHECK_FAIL ( prog_cnt ! = 0 ) ;
err :
for ( i = 0 ; i < ARRAY_SIZE ( allow_prog ) ; i + + )
if ( allow_prog [ i ] > = 0 )
close ( allow_prog [ i ] ) ;
close ( cg1 ) ;
close ( cg2 ) ;
close ( cg3 ) ;
close ( cg4 ) ;
close ( cg5 ) ;
cleanup_cgroup_environment ( ) ;
}