alistair23-linux/samples/bpf/test_cgrp2_tc.sh
Martin KaFai Lau a3f7461734 cgroup: bpf: Add an example to do cgroup checking in BPF
test_cgrp2_array_pin.c:
A userland program that creates a bpf_map (BPF_MAP_TYPE_GROUP_ARRAY),
pouplates/updates it with a cgroup2's backed fd and pins it to a
bpf-fs's file.  The pinned file can be loaded by tc and then used
by the bpf prog later.  This program can also update an existing pinned
array and it could be useful for debugging/testing purpose.

test_cgrp2_tc_kern.c:
A bpf prog which should be loaded by tc.  It is to demonstrate
the usage of bpf_skb_in_cgroup.

test_cgrp2_tc.sh:
A script that glues the test_cgrp2_array_pin.c and
test_cgrp2_tc_kern.c together.  The idea is like:
1. Load the test_cgrp2_tc_kern.o by tc
2. Use test_cgrp2_array_pin.c to populate a BPF_MAP_TYPE_CGROUP_ARRAY
   with a cgroup fd
3. Do a 'ping -6 ff02::1%ve' to ensure the packet has been
   dropped because of a match on the cgroup

Most of the lines in test_cgrp2_tc.sh is the boilerplate
to setup the cgroup/bpf-fs/net-devices/netns...etc.  It is
not bulletproof on errors but should work well enough and
give enough debug info if things did not go well.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Tejun Heo <tj@kernel.org>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-01 16:32:13 -04:00

185 lines
4.1 KiB
Bash
Executable file

#!/bin/bash
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 | egrep '(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