| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| MY_DIR=$(dirname $0) |
| # Details on the bpf prog |
| BPF_CGRP2_ARRAY_NAME='test_cgrp2_array_pin' |
| BPF_PROG="$MY_DIR/test_cgrp2_tc_kern.o" |
| BPF_SECTION='filter' |
| |
| [ -z "$TC" ] && TC='tc' |
| [ -z "$IP" ] && IP='ip' |
| |
| # Names of the veth interface, net namespace...etc. |
| HOST_IFC='ve' |
| NS_IFC='vens' |
| NS='ns' |
| |
| find_mnt() { |
| cat /proc/mounts | \ |
| awk '{ if ($3 == "'$1'" && mnt == "") { mnt = $2 }} END { print mnt }' |
| } |
| |
| # Init cgroup2 vars |
| init_cgrp2_vars() { |
| CGRP2_ROOT=$(find_mnt cgroup2) |
| if [ -z "$CGRP2_ROOT" ] |
| then |
| CGRP2_ROOT='/mnt/cgroup2' |
| MOUNT_CGRP2="yes" |
| fi |
| CGRP2_TC="$CGRP2_ROOT/tc" |
| CGRP2_TC_LEAF="$CGRP2_TC/leaf" |
| } |
| |
| # Init bpf fs vars |
| init_bpf_fs_vars() { |
| local bpf_fs_root=$(find_mnt bpf) |
| [ -n "$bpf_fs_root" ] || return -1 |
| BPF_FS_TC_SHARE="$bpf_fs_root/tc/globals" |
| } |
| |
| setup_cgrp2() { |
| case $1 in |
| start) |
| if [ "$MOUNT_CGRP2" == 'yes' ] |
| then |
| [ -d $CGRP2_ROOT ] || mkdir -p $CGRP2_ROOT |
| mount -t cgroup2 none $CGRP2_ROOT || return $? |
| fi |
| mkdir -p $CGRP2_TC_LEAF |
| ;; |
| *) |
| rmdir $CGRP2_TC_LEAF && rmdir $CGRP2_TC |
| [ "$MOUNT_CGRP2" == 'yes' ] && umount $CGRP2_ROOT |
| ;; |
| esac |
| } |
| |
| setup_bpf_cgrp2_array() { |
| local bpf_cgrp2_array="$BPF_FS_TC_SHARE/$BPF_CGRP2_ARRAY_NAME" |
| case $1 in |
| start) |
| $MY_DIR/test_cgrp2_array_pin -U $bpf_cgrp2_array -v $CGRP2_TC |
| ;; |
| *) |
| [ -d "$BPF_FS_TC_SHARE" ] && rm -f $bpf_cgrp2_array |
| ;; |
| esac |
| } |
| |
| setup_net() { |
| case $1 in |
| start) |
| $IP link add $HOST_IFC type veth peer name $NS_IFC || return $? |
| $IP link set dev $HOST_IFC up || return $? |
| sysctl -q net.ipv6.conf.$HOST_IFC.accept_dad=0 |
| |
| $IP netns add ns || return $? |
| $IP link set dev $NS_IFC netns ns || return $? |
| $IP -n $NS link set dev $NS_IFC up || return $? |
| $IP netns exec $NS sysctl -q net.ipv6.conf.$NS_IFC.accept_dad=0 |
| $TC qdisc add dev $HOST_IFC clsact || return $? |
| $TC filter add dev $HOST_IFC egress bpf da obj $BPF_PROG sec $BPF_SECTION || return $? |
| ;; |
| *) |
| $IP netns del $NS |
| $IP link del $HOST_IFC |
| ;; |
| esac |
| } |
| |
| run_in_cgrp() { |
| # Fork another bash and move it under the specified cgroup. |
| # It makes the cgroup cleanup easier at the end of the test. |
| cmd='echo $$ > ' |
| cmd="$cmd $1/cgroup.procs; exec $2" |
| bash -c "$cmd" |
| } |
| |
| do_test() { |
| run_in_cgrp $CGRP2_TC_LEAF "ping -6 -c3 ff02::1%$HOST_IFC >& /dev/null" |
| local dropped=$($TC -s qdisc show dev $HOST_IFC | tail -3 | \ |
| awk '/drop/{print substr($7, 0, index($7, ",")-1)}') |
| if [[ $dropped -eq 0 ]] |
| then |
| echo "FAIL" |
| return 1 |
| else |
| echo "Successfully filtered $dropped packets" |
| return 0 |
| fi |
| } |
| |
| do_exit() { |
| if [ "$DEBUG" == "yes" ] && [ "$MODE" != 'cleanuponly' ] |
| then |
| echo "------ DEBUG ------" |
| echo "mount: "; mount | grep -E '(cgroup2|bpf)'; echo |
| echo "$CGRP2_TC_LEAF: "; ls -l $CGRP2_TC_LEAF; echo |
| if [ -d "$BPF_FS_TC_SHARE" ] |
| then |
| echo "$BPF_FS_TC_SHARE: "; ls -l $BPF_FS_TC_SHARE; echo |
| fi |
| echo "Host net:" |
| $IP netns |
| $IP link show dev $HOST_IFC |
| $IP -6 a show dev $HOST_IFC |
| $TC -s qdisc show dev $HOST_IFC |
| echo |
| echo "$NS net:" |
| $IP -n $NS link show dev $NS_IFC |
| $IP -n $NS -6 link show dev $NS_IFC |
| echo "------ DEBUG ------" |
| echo |
| fi |
| |
| if [ "$MODE" != 'nocleanup' ] |
| then |
| setup_net stop |
| setup_bpf_cgrp2_array stop |
| setup_cgrp2 stop |
| fi |
| } |
| |
| init_cgrp2_vars |
| init_bpf_fs_vars |
| |
| while [[ $# -ge 1 ]] |
| do |
| a="$1" |
| case $a in |
| debug) |
| DEBUG='yes' |
| shift 1 |
| ;; |
| cleanup-only) |
| MODE='cleanuponly' |
| shift 1 |
| ;; |
| no-cleanup) |
| MODE='nocleanup' |
| shift 1 |
| ;; |
| *) |
| echo "test_cgrp2_tc [debug] [cleanup-only | no-cleanup]" |
| echo " debug: Print cgrp and network setup details at the end of the test" |
| echo " cleanup-only: Try to cleanup things from last test. No test will be run" |
| echo " no-cleanup: Run the test but don't do cleanup at the end" |
| echo "[Note: If no arg is given, it will run the test and do cleanup at the end]" |
| echo |
| exit -1 |
| ;; |
| esac |
| done |
| |
| trap do_exit 0 |
| |
| [ "$MODE" == 'cleanuponly' ] && exit |
| |
| setup_cgrp2 start || exit $? |
| setup_net start || exit $? |
| init_bpf_fs_vars || exit $? |
| setup_bpf_cgrp2_array start || exit $? |
| do_test |
| echo |