From 07f4e62f1c704f583740e6dd59c223819feb03ec Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:33 -0800 Subject: selftests: fib_tests: simplify ip commands in a namespace 'ip netns exec testns ip' is more efficiently handled using 'ip -netns'; runs the ip command after switching the namespace and avoids an exec. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 210 +++++++++++++++---------------- 1 file changed, 105 insertions(+), 105 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index a9154eefb2e2..672f263f8f53 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -34,23 +34,23 @@ fib_unreg_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_fail $? ip netns del testns @@ -68,40 +68,40 @@ fib_unreg_multipath_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link add dummy1 type dummy - ip netns exec testns ip link set dev dummy1 up + ip -netns testns link add dummy1 type dummy + ip -netns testns link set dev dummy1 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip address add 192.0.2.1/24 dev dummy1 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1 + ip -netns testns address add 192.0.2.1/24 dev dummy1 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 - ip netns exec testns ip route add 203.0.113.0/24 \ + ip -netns testns route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip netns exec testns ip -6 route add 2001:db8:3::/64 \ + ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. check_err $? - ip netns exec testns ip link del dev dummy1 + ip -netns testns link del dev dummy1 ip netns del testns @@ -126,26 +126,26 @@ fib_down_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_fail $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns @@ -161,31 +161,31 @@ fib_down_multipath_test_do() local down_dev=$1 local up_dev=$2 - ip netns exec testns ip route get fibmatch 203.0.113.1 \ + ip -netns testns route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null check_fail $? - ip netns exec testns ip route get fibmatch 203.0.113.1 \ + ip -netns testns route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 | \ + ip -netns testns route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 | \ + ip -netns testns route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" check_fail $? } @@ -196,52 +196,52 @@ fib_down_multipath_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link add dummy1 type dummy - ip netns exec testns ip link set dev dummy1 up + ip -netns testns link add dummy1 type dummy + ip -netns testns link set dev dummy1 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip address add 192.0.2.1/24 dev dummy1 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1 + ip -netns testns address add 192.0.2.1/24 dev dummy1 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 - ip netns exec testns ip route add 203.0.113.0/24 \ + ip -netns testns route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip netns exec testns ip -6 route add 2001:db8:3::/64 \ + ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_err $? - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? fib_down_multipath_test_do "dummy0" "dummy1" - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link set dev dummy0 up check_err $? - ip netns exec testns ip link set dev dummy1 down + ip -netns testns link set dev dummy1 down check_err $? fib_down_multipath_test_do "dummy1" "dummy0" - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_fail $? - ip netns exec testns ip link del dev dummy1 - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy1 + ip -netns testns link del dev dummy0 ip netns del testns @@ -267,56 +267,56 @@ fib_carrier_local_test() # Local routes should not be affected when carrier changes. netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link set dev dummy0 carrier on + ip -netns testns link set dev dummy0 carrier on - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.1 | \ + ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link set dev dummy0 carrier off + ip -netns testns link set dev dummy0 carrier off - ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.1 | \ + ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip address add 192.0.2.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0 + ip -netns testns address add 192.0.2.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 192.0.2.1 &> /dev/null + ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 192.0.2.1 | \ + ip -netns testns route get fibmatch 192.0.2.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns @@ -333,56 +333,56 @@ fib_carrier_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link set dev dummy0 carrier on + ip -netns testns link set dev dummy0 carrier on - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 | \ + ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link set dev dummy0 carrier off + ip -netns testns link set dev dummy0 carrier off - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 | \ + ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip address add 192.0.2.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0 + ip -netns testns address add 192.0.2.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 192.0.2.2 &> /dev/null + ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 192.0.2.2 | \ + ip -netns testns route get fibmatch 192.0.2.2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns -- cgit v1.2.3 From 1056691b26809e838da67bc2a61761017d20cfda Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:34 -0800 Subject: selftests: fib_tests: Make test results more verbose fib_tests.sh is failing in a VM: $ fib_tests.sh Running netdev unregister tests PASS: unicast route test PASS: multipath route test Running netdev down tests PASS: unicast route test PASS: multipath route test Running netdev carrier change tests PASS: local route carrier test FAIL: unicast route carrier test The last test corresponds to fib_carrier_unicast_test which 12 places that could be failing. Be more verbose in the output so a failure is easier to track down and separate test setup failures with set -e and set +e pairs. With the verbose logging it is easier to see which checks are failing: $fib_tests.sh Single path route carrier test .... Carrier down IPv4 fibmatch [ OK ] IPv6 fibmatch [ OK ] IPv4 linkdown flag set [FAIL] IPv6 linkdown flag set [FAIL] Second address added with carrier down IPv4 fibmatch [ OK ] IPv6 fibmatch [ OK ] IPv4 linkdown flag set [FAIL] IPv6 linkdown flag set [ OK ] Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 248 +++++++++++++++++-------------- 1 file changed, 135 insertions(+), 113 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 672f263f8f53..d4e0b5cb4355 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -6,17 +6,25 @@ ret=0 -check_err() -{ - if [ $ret -eq 0 ]; then - ret=$1 - fi -} +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} -check_fail() +log_test() { - if [ $1 -eq 0 ]; then + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + printf " %-60s [ OK ]\n" "${msg}" + else ret=1 + printf " %-60s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi fi } @@ -30,42 +38,44 @@ netns_create() fib_unreg_unicast_test() { - ret=0 + echo + echo "Single path route test" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link del dev dummy0 - check_err $? + set +e + echo " Nexthop device deleted" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch - no route" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch - no route" ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route test" - return 1 - fi - echo "PASS: unicast route test" } fib_unreg_multipath_test() { - ret=0 + echo + echo "Multipath route test" + + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -86,44 +96,49 @@ fib_unreg_multipath_test() ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 + set +e + echo " Start point" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link del dev dummy0 - check_err $? + set +e + echo " One nexthop device deleted" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 - multipath route removed on delete" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. - check_err $? + log_test $? 0 "IPv6 - multipath down to single path" + set -e ip -netns testns link del dev dummy1 + set +e - ip netns del testns + echo " Second nexthop device deleted" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + log_test $? 2 "IPv6 - no route" - if [ $ret -ne 0 ]; then - echo "FAIL: multipath route test" - return 1 - fi - echo "PASS: multipath route test" + ip netns del testns } fib_unreg_test() { - echo "Running netdev unregister tests" - fib_unreg_unicast_test fib_unreg_multipath_test } fib_down_unicast_test() { - ret=0 + echo + echo "Single path, admin down" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -131,29 +146,27 @@ fib_down_unicast_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " Route deleted on down" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route test" - return 1 - fi - echo "PASS: unicast route test" } fib_down_multipath_test_do() @@ -163,37 +176,39 @@ fib_down_multipath_test_do() ip -netns testns route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch on down device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch on down device" ip -netns testns route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch on up device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch on up device" ip -netns testns route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" - check_err $? + log_test $? 0 "IPv4 flags on down device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" - check_err $? + log_test $? 0 "IPv6 flags on down device" ip -netns testns route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" - check_fail $? + log_test $? 1 "IPv4 flags on up device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" - check_fail $? + log_test $? 1 "IPv6 flags on up device" } fib_down_multipath_test() { - ret=0 + echo + echo "Admin down multipath" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -214,57 +229,58 @@ fib_down_multipath_test() ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 + set +e + echo " Verify start point" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " One device down, one up" fib_down_multipath_test_do "dummy0" "dummy1" + set -e ip -netns testns link set dev dummy0 up - check_err $? ip -netns testns link set dev dummy1 down - check_err $? + set +e + echo " Other device down and up" fib_down_multipath_test_do "dummy1" "dummy0" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " Both devices down" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy1 ip -netns testns link del dev dummy0 - ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: multipath route test" - return 1 - fi - echo "PASS: multipath route test" } fib_down_test() { - echo "Running netdev down tests" - fib_down_unicast_test fib_down_multipath_test } +# Local routes should not be affected when carrier changes. fib_carrier_local_test() { - ret=0 + echo + echo "Local carrier tests - single path" - # Local routes should not be affected when carrier changes. + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -274,65 +290,71 @@ fib_carrier_local_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 - no linkdown flag" ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 - no linkdown flag" + set -e ip -netns testns link set dev dummy0 carrier off + set +e + echo " Carrier off on nexthop" ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 - linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 - linkdown flag set" + set -e ip -netns testns address add 192.0.2.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + set +e + echo " Route to local address with carrier down" ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 192.0.2.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 linkdown flag set" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: local route carrier test" - return 1 - fi - echo "PASS: local route carrier test" } fib_carrier_unicast_test() { ret=0 + echo + echo "Single path route carrier test" + netns_create "testns" + set -e ip -netns testns link add dummy0 type dummy ip -netns testns link set dev dummy0 up @@ -340,63 +362,63 @@ fib_carrier_unicast_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 no linkdown flag" ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 no linkdown flag" + set -e ip -netns testns link set dev dummy0 carrier off + set +e + echo " Carrier down" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv6 linkdown flag set" + set -e ip -netns testns address add 192.0.2.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + set +e + echo " Second address added with carrier down" ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 192.0.2.2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv6 linkdown flag set" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route carrier test" - return 1 - fi - echo "PASS: unicast route carrier test" } fib_carrier_test() { - echo "Running netdev carrier change tests" - fib_carrier_local_test fib_carrier_unicast_test } -- cgit v1.2.3 From ee395a5e722c8c7e85641c3017de8f64209ff04f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:35 -0800 Subject: selftests: fib_tests: Move admin of dummy0 to helpers Move setup and teardown of testns and dummy0 to helpers. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 100 +++++++++++-------------------- 1 file changed, 34 insertions(+), 66 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index d4e0b5cb4355..e113cfd659fc 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -28,12 +28,24 @@ log_test() fi } -netns_create() +setup() { - local testns=$1 + set -e + ip netns add testns + ip -netns testns link set dev lo up + + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + +} - ip netns add $testns - ip netns exec $testns ip link set dev lo up +cleanup() +{ + ip -netns testns link del dev dummy0 &> /dev/null + ip netns del testns } fib_unreg_unicast_test() @@ -41,14 +53,7 @@ fib_unreg_unicast_test() echo echo "Single path route test" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - set +e + setup echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null @@ -66,7 +71,7 @@ fib_unreg_unicast_test() ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch - no route" - ip netns del testns + cleanup } fib_unreg_multipath_test() @@ -75,18 +80,11 @@ fib_unreg_multipath_test() echo echo "Multipath route test" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link add dummy1 type dummy ip -netns testns link set dev dummy1 up - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip -netns testns address add 192.0.2.1/24 dev dummy1 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 @@ -124,7 +122,7 @@ fib_unreg_multipath_test() ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 - no route" - ip netns del testns + cleanup } fib_unreg_test() @@ -138,15 +136,7 @@ fib_down_unicast_test() echo echo "Single path, admin down" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - set +e + setup echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null @@ -164,9 +154,7 @@ fib_down_unicast_test() ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_down_multipath_test_do() @@ -208,18 +196,12 @@ fib_down_multipath_test() echo echo "Admin down multipath" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link add dummy1 type dummy ip -netns testns link set dev dummy1 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip -netns testns address add 192.0.2.1/24 dev dummy1 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 @@ -264,8 +246,7 @@ fib_down_multipath_test() log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy1 - ip -netns testns link del dev dummy0 - ip netns del testns + cleanup } fib_down_test() @@ -280,16 +261,10 @@ fib_carrier_local_test() echo echo "Local carrier tests - single path" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link set dev dummy0 carrier on - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 set +e echo " Start point" @@ -340,9 +315,7 @@ fib_carrier_local_test() grep -q "linkdown" log_test $? 1 "IPv6 linkdown flag set" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_carrier_unicast_test() @@ -352,16 +325,10 @@ fib_carrier_unicast_test() echo echo "Single path route carrier test" - netns_create "testns" + setup set -e - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns link set dev dummy0 carrier on - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 set +e echo " Start point" @@ -412,9 +379,7 @@ fib_carrier_unicast_test() grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_carrier_test() @@ -446,6 +411,9 @@ if [ $? -ne 0 ]; then exit 0 fi +# start clean +cleanup &> /dev/null + fib_test exit $ret -- cgit v1.2.3 From e2ba732a1681d907a6dffbaf9802aebcac233099 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:36 -0800 Subject: selftests: fib_tests: sleep after changing carrier sleep for a second after setting carrier down to allow linkwatch to propagate the change to the routing stack via netdev_state_change. As it stands there is a race setting carrier down on the dummy device and then checking the linkdown flag in the routes. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index e113cfd659fc..b617985ecdc1 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -282,6 +282,7 @@ fib_carrier_local_test() set -e ip -netns testns link set dev dummy0 carrier off + sleep 1 set +e echo " Carrier off on nexthop" -- cgit v1.2.3 From 153e1b84f477f716bc3f81e6cfae1a3d941fc7ec Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:44:06 -0800 Subject: selftests: Add FIB onlink tests Add test cases verifying FIB onlink commands work as expected in various conditions - IPv4, IPv6, main table, and VRF. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib-onlink-tests.sh | 375 ++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100755 tools/testing/selftests/net/fib-onlink-tests.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh new file mode 100755 index 000000000000..06b1d7cc12cc --- /dev/null +++ b/tools/testing/selftests/net/fib-onlink-tests.sh @@ -0,0 +1,375 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# IPv4 and IPv6 onlink tests + +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} + +# Network interfaces +# - odd in current namespace; even in peer ns +declare -A NETIFS +# default VRF +NETIFS[p1]=veth1 +NETIFS[p2]=veth2 +NETIFS[p3]=veth3 +NETIFS[p4]=veth4 +# VRF +NETIFS[p5]=veth5 +NETIFS[p6]=veth6 +NETIFS[p7]=veth7 +NETIFS[p8]=veth8 + +# /24 network +declare -A V4ADDRS +V4ADDRS[p1]=169.254.1.1 +V4ADDRS[p2]=169.254.1.2 +V4ADDRS[p3]=169.254.3.1 +V4ADDRS[p4]=169.254.3.2 +V4ADDRS[p5]=169.254.5.1 +V4ADDRS[p6]=169.254.5.2 +V4ADDRS[p7]=169.254.7.1 +V4ADDRS[p8]=169.254.7.2 + +# /64 network +declare -A V6ADDRS +V6ADDRS[p1]=2001:db8:101::1 +V6ADDRS[p2]=2001:db8:101::2 +V6ADDRS[p3]=2001:db8:301::1 +V6ADDRS[p4]=2001:db8:301::2 +V6ADDRS[p5]=2001:db8:501::1 +V6ADDRS[p6]=2001:db8:501::2 +V6ADDRS[p7]=2001:db8:701::1 +V6ADDRS[p8]=2001:db8:701::2 + +# Test networks: +# [1] = default table +# [2] = VRF +# +# /32 host routes +declare -A TEST_NET4 +TEST_NET4[1]=169.254.101 +TEST_NET4[2]=169.254.102 +# /128 host routes +declare -A TEST_NET6 +TEST_NET6[1]=2001:db8:101 +TEST_NET6[2]=2001:db8:102 + +# connected gateway +CONGW[1]=169.254.1.254 +CONGW[2]=169.254.5.254 + +# recursive gateway +RECGW4[1]=169.254.11.254 +RECGW4[2]=169.254.12.254 +RECGW6[1]=2001:db8:11::64 +RECGW6[2]=2001:db8:12::64 + +# for v4 mapped to v6 +declare -A TEST_NET4IN6IN6 +TEST_NET4IN6[1]=10.1.1.254 +TEST_NET4IN6[2]=10.2.1.254 + +# mcast address +MCAST6=ff02::1 + + +PEER_NS=bart +PEER_CMD="ip netns exec ${PEER_NS}" +VRF=lisa +VRF_TABLE=1101 +PBR_TABLE=101 + +################################################################################ +# utilities + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + nsuccess=$((nsuccess+1)) + printf "\n TEST: %-50s [ OK ]\n" "${msg}" + else + nfail=$((nfail+1)) + printf "\n TEST: %-50s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi +} + +log_section() +{ + echo + echo "######################################################################" + echo "TEST SECTION: $*" + echo "######################################################################" +} + +log_subsection() +{ + echo + echo "#########################################" + echo "TEST SUBSECTION: $*" +} + +run_cmd() +{ + echo + echo "COMMAND: $*" + eval $* +} + +get_linklocal() +{ + local dev=$1 + local pfx + local addr + + addr=$(${pfx} ip -6 -br addr show dev ${dev} | \ + awk '{ + for (i = 3; i <= NF; ++i) { + if ($i ~ /^fe80/) + print $i + } + }' + ) + addr=${addr/\/*} + + [ -z "$addr" ] && return 1 + + echo $addr + + return 0 +} + +################################################################################ +# + +setup() +{ + echo + echo "########################################" + echo "Configuring interfaces" + + set -e + + # create namespace + ip netns add ${PEER_NS} + ip -netns ${PEER_NS} li set lo up + + # add vrf table + ip li add ${VRF} type vrf table ${VRF_TABLE} + ip li set ${VRF} up + ip ro add table ${VRF_TABLE} unreachable default + ip -6 ro add table ${VRF_TABLE} unreachable default + + # create test interfaces + ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} + ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]} + ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]} + ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]} + + # enslave vrf interfaces + for n in 5 7; do + ip li set ${NETIFS[p${n}]} vrf ${VRF} + done + + # add addresses + for n in 1 3 5 7; do + ip li set ${NETIFS[p${n}]} up + ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} + done + + # move peer interfaces to namespace and add addresses + for n in 2 4 6 8; do + ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up + ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} + done + + set +e + + # let DAD complete - assume default of 1 probe + sleep 1 +} + +cleanup() +{ + # make sure we start from a clean slate + ip netns del ${PEER_NS} 2>/dev/null + for n in 1 3 5 7; do + ip link del ${NETIFS[p${n}]} 2>/dev/null + done + ip link del ${VRF} 2>/dev/null + ip ro flush table ${VRF_TABLE} + ip -6 ro flush table ${VRF_TABLE} +} + +################################################################################ +# IPv4 tests +# + +run_ip() +{ + local table="$1" + local prefix="$2" + local gw="$3" + local dev="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink + log_test $? ${exp_rc} "${desc}" +} + +valid_onlink_ipv4() +{ + # - unicast connected, unicast recursive + # + log_subsection "default VRF - main table" + + run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected" + run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive" + + log_subsection "VRF ${VRF}" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" + + log_subsection "VRF device, PBR table" + + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" +} + +invalid_onlink_ipv4() +{ + run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \ + "Invalid gw - local unicast address" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \ + "Invalid gw - local unicast address, VRF" + + run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given" + + run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \ + "Gateway resolves to wrong nexthop device" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \ + "Gateway resolves to wrong nexthop device - VRF" +} + +################################################################################ +# IPv6 tests +# + +run_ip6() +{ + local table="$1" + local prefix="$2" + local gw="$3" + local dev="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink + log_test $? ${exp_rc} "${desc}" +} + +valid_onlink_ipv6() +{ + # - unicast connected, unicast recursive, v4-mapped + # + log_subsection "default VRF - main table" + + run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected" + run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive" + run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped" + + log_subsection "VRF ${VRF}" + + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" + + log_subsection "VRF device, PBR table" + + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" +} + +invalid_onlink_ipv6() +{ + local lladdr + + lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1 + + run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \ + "Invalid gw - local unicast address" + run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \ + "Invalid gw - local linklocal address" + run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \ + "Invalid gw - multicast address" + + lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1 + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \ + "Invalid gw - local unicast address, VRF" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \ + "Invalid gw - local linklocal address, VRF" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \ + "Invalid gw - multicast address, VRF" + + run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \ + "No nexthop device given" + + # default VRF validation is done against LOCAL table + # run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \ + # "Gateway resolves to wrong nexthop device" + + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \ + "Gateway resolves to wrong nexthop device - VRF" +} + +run_onlink_tests() +{ + log_section "IPv4 onlink" + log_subsection "Valid onlink commands" + valid_onlink_ipv4 + log_subsection "Invalid onlink commands" + invalid_onlink_ipv4 + + log_section "IPv6 onlink" + log_subsection "Valid onlink commands" + valid_onlink_ipv6 + invalid_onlink_ipv6 +} + +################################################################################ +# main + +nsuccess=0 +nfail=0 + +cleanup +setup +run_onlink_tests +cleanup + +if [ "$TESTS" != "none" ]; then + printf "\nTests passed: %3d\n" ${nsuccess} + printf "Tests failed: %3d\n" ${nfail} +fi -- cgit v1.2.3 From 41757dcb0c3d8446c549e55163c9fd9561fcf599 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 13 Feb 2018 14:19:15 +0100 Subject: selftests/bpf: fix Makefile for cgroup_helpers.c The current selftests Makefile construct result in cgroup_helpers.c gets compiled together with all the TEST_GEN_PROGS. And it also result in invoking the libbpf Makefile two times (tools/lib/bpf). These issues were introduced in commit 9d1f15941967 ("bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/"). The only test program that requires the cgroup helpers is 'test_dev_cgroup'. Thus, create a make target $(OUTPUT)/test_dev_cgroup that extend[1] the 'prerequisite' for the 'stem' %-style pattern in ../lib.mk, for this particular test program. Reviewers notice the make-rules in tools/testing/selftests/lib.mk differ from the normal kernel kbuild rules, and it is practical to use 'make -p' to follow how these 'Implicit/static pattern stem' gets expanded. [1] https://www.gnu.org/software/make/manual/html_node/Static-Usage.html Fixes: 9d1f15941967 ("bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 5c43c187f27c..8567a858b789 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -35,12 +35,14 @@ TEST_GEN_PROGS_EXTENDED = test_libbpf_open include ../lib.mk -BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c +BPFOBJ := $(OUTPUT)/libbpf.a $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a +$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c + .PHONY: force # force a rebuild of BPFOBJ when its dependencies are updated -- cgit v1.2.3 From 615a9474985799c8b48645b8e95a9b9f0691f56a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 13 Feb 2018 10:35:05 -0800 Subject: tools/bpf: adjust rlimit RLIMIT_MEMLOCK for test_tcpbpf_user The default rlimit RLIMIT_MEMLOCK is 64KB. In certain cases, e.g. in a test machine mimicking our production system, this test may fail due to unable to charge the required memory for map creation: # ./test_tcpbpf_user libbpf: failed to create map (name: 'global_map'): Operation not permitted libbpf: failed to load object 'test_tcpbpf_kern.o' FAILED: load_bpf_file failed for: test_tcpbpf_kern.o Changing the default rlimit RLIMIT_MEMLOCK to unlimited makes the test always pass. Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_tcpbpf_user.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index 95a370f3d378..5d73db416460 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,6 +44,7 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, int main(int argc, char **argv) { + struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; const char *file = "test_tcpbpf_kern.o"; struct tcpbpf_globals g = {0}; int cg_fd, prog_fd, map_fd; @@ -54,6 +57,9 @@ int main(int argc, char **argv) int pid; int rv; + if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) + perror("Unable to lift memlock rlimit"); + if (argc > 1 && strcmp(argv[1], "-d") == 0) debug_flag = true; -- cgit v1.2.3 From 95f87a9706d0a55ff02a652bc8f1b3f7d51bf5eb Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:34 -0800 Subject: selftests/bpf: Print unexpected output on fail This makes it easier to debug off-hand when the error message isn't exactly as expected. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index c0f16e93f9bd..6cf9bd6f08b7 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11291,7 +11291,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, goto fail_log; } if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) { - printf("FAIL\nUnexpected error message!\n"); + printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n", + expected_err, bpf_vlog); goto fail_log; } } -- cgit v1.2.3 From d0a0e4956f6c20754ef67db6dfb9746e85ecdcb5 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:35 -0800 Subject: selftests/bpf: Count tests skipped by unpriv When priviliged tests are skipped due to user rights, count the number of skipped tests so it's more obvious that the test did not check everything. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 6cf9bd6f08b7..7ab02526c403 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11378,7 +11378,7 @@ out: static int do_test(bool unpriv, unsigned int from, unsigned int to) { - int i, passes = 0, errors = 0; + int i, passes = 0, errors = 0, skips = 0; for (i = from; i < to; i++) { struct bpf_test *test = &tests[i]; @@ -11395,13 +11395,17 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) set_admin(true); } - if (!unpriv) { + if (unpriv) { + printf("#%d/p %s SKIP\n", i, test->descr); + skips++; + } else { printf("#%d/p %s ", i, test->descr); do_test_single(test, false, &passes, &errors); } } - printf("Summary: %d PASSED, %d FAILED\n", passes, errors); + printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, + skips, errors); return errors ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3 From 0a67487403683852e05fea97208ad7b0ed820115 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:36 -0800 Subject: selftests/bpf: Only run tests if !bpf_disabled The "kernel.unprivileged_bpf_disabled" sysctl, if enabled, causes all unprivileged tests to fail because it permanently disables unprivileged BPF access for the currently running kernel. Skip the relevant tests if the user attempts to run the testsuite with this sysctl enabled. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 7ab02526c403..2971ba2829ac 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -57,6 +57,9 @@ #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) +#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" +static bool unpriv_disabled = false; + struct bpf_test { const char *descr; struct bpf_insn insns[MAX_INSNS]; @@ -11376,6 +11379,17 @@ out: return ret; } +static void get_unpriv_disabled() +{ + char buf[2]; + FILE *fd; + + fd = fopen("/proc/sys/"UNPRIV_SYSCTL, "r"); + if (fgets(buf, 2, fd) == buf && atoi(buf)) + unpriv_disabled = true; + fclose(fd); +} + static int do_test(bool unpriv, unsigned int from, unsigned int to) { int i, passes = 0, errors = 0, skips = 0; @@ -11386,7 +11400,10 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) /* Program types that are not supported by non-root we * skip right away. */ - if (!test->prog_type) { + if (!test->prog_type && unpriv_disabled) { + printf("#%d/u %s SKIP\n", i, test->descr); + skips++; + } else if (!test->prog_type) { if (!unpriv) set_admin(false); printf("#%d/u %s ", i, test->descr); @@ -11433,6 +11450,13 @@ int main(int argc, char **argv) } } + get_unpriv_disabled(); + if (unpriv && unpriv_disabled) { + printf("Cannot run as unprivileged user with sysctl %s.\n", + UNPRIV_SYSCTL); + return EXIT_FAILURE; + } + setrlimit(RLIMIT_MEMLOCK, unpriv ? &rlim : &rinf); return do_test(unpriv, from, to); } -- cgit v1.2.3 From f87c7f646c6f704b29504d63c4ab965584c4aacb Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:19 -0500 Subject: tools: tc-testing: Command line parms Separate the functionality of the command line parameters into "selection" parameters, "action" parameters and other parameters. "Selection" parameters are for choosing which tests on which to act. "Action" parameters are for choosing what to do with the selected tests. "Other" parameters are for global effect (like "help" or "verbose"). With this commit, we add the ability to name a directory as another selection mechanism. We can accumulate a number of tests by directory, file, category, or even by test id, instead of being constrained to run all tests in one collection or just one test. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../creating-testcases/AddingTestCases.txt | 35 +++- tools/testing/selftests/tc-testing/tdc.py | 209 +++++++++++++-------- tools/testing/selftests/tc-testing/tdc_helper.py | 15 +- 3 files changed, 164 insertions(+), 95 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt index 00438331ba47..17b267dedbd9 100644 --- a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt +++ b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt @@ -12,14 +12,18 @@ template.json for the required JSON format for test cases. Include the 'id' field, but do not assign a value. Running tdc with the -i option will generate a unique ID for that test case. -tdc will recursively search the 'tc' subdirectory for .json files. Any -test case files you create in these directories will automatically be included. -If you wish to store your custom test cases elsewhere, be sure to run tdc -with the -f argument and the path to your file. +tdc will recursively search the 'tc-tests' subdirectory (or the +directories named with the -D option) for .json files. Any test case +files you create in these directories will automatically be included. +If you wish to store your custom test cases elsewhere, be sure to run +tdc with the -f argument and the path to your file, or the -D argument +and the path to your directory(ies). -Be aware of required escape characters in the JSON data - particularly when -defining the match pattern. Refer to the tctests.json file for examples when -in doubt. +Be aware of required escape characters in the JSON data - particularly +when defining the match pattern. Refer to the supplied json test files +for examples when in doubt. The match pattern is written in json, and +will be used by python. So the match pattern will be a python regular +expression, but should be written using json syntax. TEST CASE STRUCTURE @@ -69,7 +73,8 @@ SETUP/TEARDOWN ERRORS If an error is detected during the setup/teardown process, execution of the tests will immediately stop with an error message and the namespace in which the tests are run will be destroyed. This is to prevent inaccurate results -in the test cases. +in the test cases. tdc will output a series of TAP results for the skipped +tests. Repeated failures of the setup/teardown may indicate a problem with the test case, or possibly even a bug in one of the commands that are not being tested. @@ -79,3 +84,17 @@ so that it doesn't halt the script for an error that doesn't matter. Turn the individual command into a list, with the command being first, followed by all acceptable exit codes for the command. +Example: + +A pair of setup commands. The first can have exit code 0, 1 or 255, the +second must have exit code 0. + + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + "$TC actions add action reclassify index 65536" + ], diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index fc373fdf2bdc..ef3a8881e458 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -209,20 +209,41 @@ def set_args(parser): """ Set the command line arguments for tdc. """ - parser.add_argument('-p', '--path', type=str, - help='The full path to the tc executable to use') - parser.add_argument('-c', '--category', type=str, nargs='?', const='+c', - help='Run tests only from the specified category, or if no category is specified, list known categories.') - parser.add_argument('-f', '--file', type=str, - help='Run tests from the specified file') - parser.add_argument('-l', '--list', type=str, nargs='?', const="++", metavar='CATEGORY', - help='List all test cases, or those only within the specified category') - parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID', - help='Display the test case with specified id') - parser.add_argument('-e', '--execute', type=str, nargs=1, metavar='ID', - help='Execute the single test case with specified ID') - parser.add_argument('-i', '--id', action='store_true', dest='gen_id', - help='Generate ID numbers for new test cases') + parser.add_argument( + '-p', '--path', type=str, + help='The full path to the tc executable to use') + sg = parser.add_argument_group( + 'selection', 'select which test cases: ' + + 'files plus directories; filtered by categories plus testids') + ag = parser.add_argument_group( + 'action', 'select action to perform on selected test cases') + + sg.add_argument( + '-D', '--directory', nargs='+', metavar='DIR', + help='Collect tests from the specified directory(ies) ' + + '(default [tc-tests])') + sg.add_argument( + '-f', '--file', nargs='+', metavar='FILE', + help='Run tests from the specified file(s)') + sg.add_argument( + '-c', '--category', nargs='*', metavar='CATG', default=['+c'], + help='Run tests only from the specified category/ies, ' + + 'or if no category/ies is/are specified, list known categories.') + sg.add_argument( + '-e', '--execute', nargs='+', metavar='ID', + help='Execute the specified test cases with specified IDs') + ag.add_argument( + '-l', '--list', action='store_true', + help='List all test cases, or those only within the specified category') + ag.add_argument( + '-s', '--show', action='store_true', dest='showID', + help='Display the selected test cases') + ag.add_argument( + '-i', '--id', action='store_true', dest='gen_id', + help='Generate ID numbers for new test cases') + parser.add_argument( + '-v', '--verbose', action='count', default=0, + help='Show the commands that are being run') parser.add_argument('-d', '--device', help='Execute the test case in flower category') return parser @@ -257,7 +278,16 @@ def check_case_id(alltests): Check for duplicate test case IDs. """ idl = get_id_list(alltests) + # print('check_case_id: idl is {}'.format(idl)) + # answer = list() + # for x in idl: + # print('Looking at {}'.format(x)) + # print('what the heck is idl.count(x)??? {}'.format(idl.count(x))) + # if idl.count(x) > 1: + # answer.append(x) + # print(' ... append it {}'.format(x)) return [x for x in idl if idl.count(x) > 1] + return answer def does_id_exist(alltests, newid): @@ -300,28 +330,96 @@ def generate_case_ids(alltests): json.dump(testlist, outfile, indent=4) outfile.close() +def filter_tests_by_id(args, testlist): + ''' + Remove tests from testlist that are not in the named id list. + If id list is empty, return empty list. + ''' + newlist = list() + if testlist and args.execute: + target_ids = args.execute + + if isinstance(target_ids, list) and (len(target_ids) > 0): + newlist = list(filter(lambda x: x['id'] in target_ids, testlist)) + return newlist + +def filter_tests_by_category(args, testlist): + ''' + Remove tests from testlist that are not in a named category. + ''' + answer = list() + if args.category and testlist: + test_ids = list() + for catg in set(args.category): + if catg == '+c': + continue + print('considering category {}'.format(catg)) + for tc in testlist: + if catg in tc['category'] and tc['id'] not in test_ids: + answer.append(tc) + test_ids.append(tc['id']) + + return answer def get_test_cases(args): """ If a test case file is specified, retrieve tests from that file. Otherwise, glob for all json files in subdirectories and load from each one. + Also, if requested, filter by category, and add tests matching + certain ids. """ import fnmatch - if args.file != None: - if not os.path.isfile(args.file): - print("The specified test case file " + args.file + " does not exist.") - exit(1) - flist = [args.file] - else: - flist = [] - for root, dirnames, filenames in os.walk('tc-tests'): + + flist = [] + testdirs = ['tc-tests'] + + if args.file: + # at least one file was specified - remove the default directory + testdirs = [] + + for ff in args.file: + if not os.path.isfile(ff): + print("IGNORING file " + ff + " \n\tBECAUSE does not exist.") + else: + flist.append(os.path.abspath(ff)) + + if args.directory: + testdirs = args.directory + + for testdir in testdirs: + for root, dirnames, filenames in os.walk(testdir): for filename in fnmatch.filter(filenames, '*.json'): - flist.append(os.path.join(root, filename)) - alltests = list() + candidate = os.path.abspath(os.path.join(root, filename)) + if candidate not in testdirs: + flist.append(candidate) + + alltestcases = list() for casefile in flist: - alltests = alltests + (load_from_file(casefile)) - return alltests + alltestcases = alltestcases + (load_from_file(casefile)) + + allcatlist = get_test_categories(alltestcases) + allidlist = get_id_list(alltestcases) + + testcases_by_cats = get_categorized_testlist(alltestcases, allcatlist) + idtestcases = filter_tests_by_id(args, alltestcases) + cattestcases = filter_tests_by_category(args, alltestcases) + + cat_ids = [x['id'] for x in cattestcases] + if args.execute: + if args.category: + alltestcases = cattestcases + [x for x in idtestcases if x['id'] not in cat_ids] + else: + alltestcases = idtestcases + else: + if cat_ids: + alltestcases = cattestcases + else: + # just accept the existing value of alltestcases, + # which has been filtered by file/directory + pass + + return allcatlist, allidlist, testcases_by_cats, alltestcases def set_operation_mode(args): @@ -330,10 +428,9 @@ def set_operation_mode(args): what the script should do for this run, and call the appropriate function. """ - alltests = get_test_cases(args) + ucat, idlist, testcases, alltests = get_test_cases(args) if args.gen_id: - idlist = get_id_list(alltests) if (has_blank_ids(idlist)): alltests = generate_case_ids(alltests) else: @@ -347,42 +444,20 @@ def set_operation_mode(args): print("Please correct them before continuing.") exit(1) - ucat = get_test_categories(alltests) - if args.showID: - show_test_case_by_id(alltests, args.showID[0]) + for atest in alltests: + print_test_case(atest) exit(0) - if args.execute: - target_id = args.execute[0] - else: - target_id = "" - - if args.category: - if (args.category == '+c'): - print("Available categories:") - print_sll(ucat) - exit(0) - else: - target_category = args.category - else: - target_category = "" - - - testcases = get_categorized_testlist(alltests, ucat) + if isinstance(args.category, list) and (len(args.category) == 0): + print("Available categories:") + print_sll(ucat) + exit(0) if args.list: - if (args.list == "++"): + if args.list: list_test_cases(alltests) exit(0) - elif(len(args.list) > 0): - if (args.list not in ucat): - print("Unknown category " + args.list) - print("Available categories:") - print_sll(ucat) - exit(1) - list_test_cases(testcases[args.list]) - exit(0) if (os.geteuid() != 0): print("This script must be run with root privileges.\n") @@ -390,24 +465,8 @@ def set_operation_mode(args): ns_create() - if (len(target_category) == 0): - if (len(target_id) > 0): - alltests = list(filter(lambda x: target_id in x['id'], alltests)) - if (len(alltests) == 0): - print("Cannot find a test case with ID matching " + target_id) - exit(1) - catresults = test_runner(alltests, args) - print("All test results: " + "\n\n" + catresults) - elif (len(target_category) > 0): - if (target_category == "flower") and args.device == None: - print("Please specify a NIC device (-d) to run category flower") - exit(1) - if (target_category not in ucat): - print("Specified category is not present in this file.") - exit(1) - else: - catresults = test_runner(testcases[target_category], args) - print("Category " + target_category + "\n\n" + catresults) + catresults = test_runner(alltests, args) + print('All test results: \n\n{}'.format(catresults)) ns_destroy() diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py index db381120a566..9f35c96c88a0 100644 --- a/tools/testing/selftests/tc-testing/tdc_helper.py +++ b/tools/testing/selftests/tc-testing/tdc_helper.py @@ -57,20 +57,11 @@ def print_sll(items): def print_test_case(tcase): """ Pretty-printing of a given test case. """ + print('\n==============\nTest {}\t{}\n'.format(tcase['id'], tcase['name'])) for k in tcase.keys(): if (isinstance(tcase[k], list)): print(k + ":") print_list(tcase[k]) else: - print(k + ": " + tcase[k]) - - -def show_test_case_by_id(testlist, caseID): - """ Find the specified test case to pretty-print. """ - if not any(d.get('id', None) == caseID for d in testlist): - print("That ID does not exist.") - exit(1) - else: - print_test_case(next((d for d in testlist if d['id'] == caseID))) - - + if not ((k == 'id') or (k == 'name')): + print(k + ": " + str(tcase[k])) -- cgit v1.2.3 From 6fac733d9d07c4fcc349a44add75c6435cc3f18c Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:20 -0500 Subject: tools: tc-testing: Refactor test-runner Split the test_runner function into the loop part (test_runner) and the contents (run_one_test) for maintainability. It makes it a little easier to catch exceptions in an individual test, and keep going (and flush a bunch of tap results for the skipped tests). Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 81 ++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 29 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index ef3a8881e458..a2624eda34db 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -85,9 +85,42 @@ def prepare_env(cmdlist): print("\nError message:") print(foutput) print("\nAborting test run.") - ns_destroy() - exit(1) + # ns_destroy() + raise Exception('prepare_env did not complete successfully') + +def run_one_test(index, tidx): + result = True + tresult = "" + tap = "" + print("Test " + tidx["id"] + ": " + tidx["name"]) + prepare_env(tidx["setup"]) + (p, procout) = exec_cmd(tidx["cmdUnderTest"]) + exit_code = p.returncode + + if (exit_code != int(tidx["expExitCode"])): + result = False + print("exit:", exit_code, int(tidx["expExitCode"])) + print(procout) + else: + match_pattern = re.compile(str(tidx["matchPattern"]), + re.DOTALL | re.MULTILINE) + (p, procout) = exec_cmd(tidx["verifyCmd"]) + match_index = re.findall(match_pattern, procout) + if len(match_index) != int(tidx["matchCount"]): + result = False + + if not result: + tresult += "not " + tresult += "ok {} - {} # {}\n".format(str(index), tidx['id'], tidx["name"]) + tap += tresult + if result == False: + tap += procout + + prepare_env(tidx["teardown"]) + index += 1 + + return tap def test_runner(filtered_tests, args): """ @@ -104,37 +137,27 @@ def test_runner(filtered_tests, args): tap = str(index) + ".." + str(tcount) + "\n" for tidx in testlist: - result = True - tresult = "" if "flower" in tidx["category"] and args.device == None: continue - print("Test " + tidx["id"] + ": " + tidx["name"]) - prepare_env(tidx["setup"]) - (p, procout) = exec_cmd(tidx["cmdUnderTest"]) - exit_code = p.returncode - - if (exit_code != int(tidx["expExitCode"])): - result = False - print("exit:", exit_code, int(tidx["expExitCode"])) - print(procout) - else: - match_pattern = re.compile(str(tidx["matchPattern"]), re.DOTALL) - (p, procout) = exec_cmd(tidx["verifyCmd"]) - match_index = re.findall(match_pattern, procout) - if len(match_index) != int(tidx["matchCount"]): - result = False - - if result == True: - tresult += "ok " - else: - tresult += "not ok " - tap += tresult + str(index) + " " + tidx["id"] + " " + tidx["name"] + "\n" + try: + badtest = tidx # in case it goes bad + tap += run_one_test(index, tidx) + except Exception as ee: + print('Exception {} (caught in test_runner, running test {} {} {})'. + format(ee, index, tidx['id'], tidx['name'])) + break + index += 1 - if result == False: - tap += procout + count = index + tap += 'about to flush the tap output if tests need to be skipped\n' + if tcount + 1 != index: + for tidx in testlist[index - 1:]: + msg = 'skipped - previous setup or teardown failed' + tap += 'ok {} - {} # {} {} {} \n'.format( + count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) + count += 1 - prepare_env(tidx["teardown"]) - index += 1 + tap += 'done flushing skipped test tap output\n' return tap -- cgit v1.2.3 From 93707cbabcc8baf2b2b5f4a99c1f08ee83eb7abd Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:21 -0500 Subject: tools: tc-testing: Introduce plugin architecture This should be a general test architecture, and yet allow specific tests to be done. Introduce a plugin architecture. An individual test has 4 stages, setup/execute/verify/teardown. Each plugin gets a chance to run a function at each stage, plus one call before all the tests are called ("pre" suite) and one after all the tests are called ("post" suite). In addition, just before each command is executed, the plugin gets a chance to modify the command using the "adjust_command" hook. This makes the test suite quite flexible. Future patches will take some functionality out of the tdc.py script and place it in plugins. To use the plugins, place the implementation in the plugins directory and run tdc.py. It will notice the plugins and use them. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/TdcPlugin.py | 74 +++++++ .../tc-testing/creating-plugins/AddingPlugins.txt | 104 ++++++++++ .../selftests/tc-testing/plugin-lib/README-PLUGINS | 27 +++ .../selftests/tc-testing/plugins/__init__.py | 0 tools/testing/selftests/tc-testing/tdc.py | 221 +++++++++++++++------ 5 files changed, 368 insertions(+), 58 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/TdcPlugin.py create mode 100644 tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS create mode 100644 tools/testing/selftests/tc-testing/plugins/__init__.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/TdcPlugin.py b/tools/testing/selftests/tc-testing/TdcPlugin.py new file mode 100644 index 000000000000..3ee9a6dacb52 --- /dev/null +++ b/tools/testing/selftests/tc-testing/TdcPlugin.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +class TdcPlugin: + def __init__(self): + super().__init__() + print(' -- {}.__init__'.format(self.sub_class)) + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + self.testcount = testcount + self.testidlist = testidlist + if self.args.verbose > 1: + print(' -- {}.pre_suite'.format(self.sub_class)) + + def post_suite(self, index): + '''run commands after test_runner completes the test loop + index is the last ordinal number of test that was attempted''' + if self.args.verbose > 1: + print(' -- {}.post_suite'.format(self.sub_class)) + + def pre_case(self, test_ordinal, testid): + '''run commands before test_runner does one test''' + if self.args.verbose > 1: + print(' -- {}.pre_case'.format(self.sub_class)) + self.args.testid = testid + self.args.test_ordinal = test_ordinal + + def post_case(self): + '''run commands after test_runner does one test''' + if self.args.verbose > 1: + print(' -- {}.post_case'.format(self.sub_class)) + + def pre_execute(self): + '''run command before test-runner does the execute step''' + if self.args.verbose > 1: + print(' -- {}.pre_execute'.format(self.sub_class)) + + def post_execute(self): + '''run command after test-runner does the execute step''' + if self.args.verbose > 1: + print(' -- {}.post_execute'.format(self.sub_class)) + + def adjust_command(self, stage, command): + '''adjust the command''' + if self.args.verbose > 1: + print(' -- {}.adjust_command {}'.format(self.sub_class, stage)) + + # if stage == 'pre': + # pass + # elif stage == 'setup': + # pass + # elif stage == 'execute': + # pass + # elif stage == 'verify': + # pass + # elif stage == 'teardown': + # pass + # elif stage == 'post': + # pass + # else: + # pass + + return command + + def add_args(self, parser): + '''Get the plugin args from the command line''' + self.argparser = parser + return self.argparser + + def check_args(self, args, remaining): + '''Check that the args are set correctly''' + self.args = args + if self.args.verbose > 1: + print(' -- {}.check_args'.format(self.sub_class)) diff --git a/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt new file mode 100644 index 000000000000..c18f88d09360 --- /dev/null +++ b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt @@ -0,0 +1,104 @@ +tdc - Adding plugins for tdc + +Author: Brenda J. Butler - bjb@mojatatu.com + +ADDING PLUGINS +-------------- + +A new plugin should be written in python as a class that inherits from TdcPlugin. +There are some examples in plugin-lib. + +The plugin can be used to add functionality to the test framework, +such as: + +- adding commands to be run before and/or after the test suite +- adding commands to be run before and/or after the test cases +- adding commands to be run before and/or after the execute phase of the test cases +- ability to alter the command to be run in any phase: + pre (the pre-suite stage) + prepare + execute + verify + teardown + post (the post-suite stage) +- ability to add to the command line args, and use them at run time + + +The functions in the class should follow the following interfaces: + + def __init__(self) + def pre_suite(self, testcount, testidlist) # see "PRE_SUITE" below + def post_suite(self, ordinal) # see "SKIPPING" below + def pre_case(self, test_ordinal, testid) # see "PRE_CASE" below + def post_case(self) + def pre_execute(self) + def post_execute(self) + def adjust_command(self, stage, command) # see "ADJUST" below + def add_args(self, parser) # see "ADD_ARGS" below + def check_args(self, args, remaining) # see "CHECK_ARGS" below + + +PRE_SUITE + +This method takes a testcount (number of tests to be run) and +testidlist (array of test ids for tests that will be run). This is +useful for various things, including when an exception occurs and the +rest of the tests must be skipped. The info is stored in the object, +and the post_suite method can refer to it when dumping the "skipped" +TAP output. The tdc.py script will do that for the test suite as +defined in the test case, but if the plugin is being used to run extra +tests on each test (eg, check for memory leaks on associated +co-processes) then that other tap output can be generated in the +post-suite method using this info passed in to the pre_suite method. + + +SKIPPING + +The post_suite method will receive the ordinal number of the last +test to be attempted. It can use this info when outputting +the TAP output for the extra test cases. + + +PRE_CASE + +The pre_case method will receive the ordinal number of the test +and the test id. Useful for outputing the extra test results. + + +ADJUST + +The adjust_command method receives a string representing +the execution stage and a string which is the actual command to be +executed. The plugin can adjust the command, based on the stage of +execution. + +The stages are represented by the following strings: + + 'pre' + 'setup' + 'command' + 'verify' + 'teardown' + 'post' + +The adjust_command method must return the adjusted command so tdc +can use it. + + +ADD_ARGS + +The add_args method receives the argparser object and can add +arguments to it. Care should be taken that the new arguments do not +conflict with any from tdc.py or from other plugins that will be used +concurrently. + +The add_args method should return the argparser object. + + +CHECK_ARGS + +The check_args method is so that the plugin can do validation on +the args, if needed. If there is a problem, and Exception should +be raised, with a string that explains the problem. + +eg: raise Exception('plugin xxx, arg -y is wrong, fix it') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS new file mode 100644 index 000000000000..aa8a2669702b --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS @@ -0,0 +1,27 @@ +tdc.py will look for plugins in a directory plugins off the cwd. +Make a set of numbered symbolic links from there to the actual plugins. +Eg: + +tdc.py +plugin-lib/ +plugins/ + __init__.py + 10-rootPlugin.py -> ../plugin-lib/rootPlugin.py + 20-valgrindPlugin.py -> ../plugin-lib/valgrindPlugin.py + 30-nsPlugin.py -> ../plugin-lib/nsPlugin.py + + +tdc.py will find them and use them. + + +rootPlugin + Check if the uid is root. If not, bail out. + +valgrindPlugin + Run the command under test with valgrind, and produce an extra set of TAP results for the memory tests. + This plugin will write files to the cwd, called vgnd-xxx.log. These will contain + the valgrind output for test xxx. Any file matching the glob 'vgnd-*.log' will be + deleted at the end of the run. + +nsPlugin + Run all the commands in a network namespace. diff --git a/tools/testing/selftests/tc-testing/plugins/__init__.py b/tools/testing/selftests/tc-testing/plugins/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index a2624eda34db..3e6f9f2e1691 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -11,17 +11,91 @@ import re import os import sys import argparse +import importlib import json import subprocess +import time from collections import OrderedDict from string import Template from tdc_config import * from tdc_helper import * +import TdcPlugin USE_NS = True +class PluginMgr: + def __init__(self, argparser): + super().__init__() + self.plugins = {} + self.plugin_instances = [] + self.args = [] + self.argparser = argparser + + # TODO, put plugins in order + plugindir = os.getenv('TDC_PLUGIN_DIR', './plugins') + for dirpath, dirnames, filenames in os.walk(plugindir): + for fn in filenames: + if (fn.endswith('.py') and + not fn == '__init__.py' and + not fn.startswith('#') and + not fn.startswith('.#')): + mn = fn[0:-3] + foo = importlib.import_module('plugins.' + mn) + self.plugins[mn] = foo + self.plugin_instances.append(foo.SubPlugin()) + + def call_pre_suite(self, testcount, testidlist): + for pgn_inst in self.plugin_instances: + pgn_inst.pre_suite(testcount, testidlist) + + def call_post_suite(self, index): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_suite(index) + + def call_pre_case(self, test_ordinal, testid): + for pgn_inst in self.plugin_instances: + try: + pgn_inst.pre_case(test_ordinal, testid) + except Exception as ee: + print('exception {} in call to pre_case for {} plugin'. + format(ee, pgn_inst.__class__)) + print('test_ordinal is {}'.format(test_ordinal)) + print('testid is {}'.format(testid)) + raise + + def call_post_case(self): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_case() + + def call_pre_execute(self): + for pgn_inst in self.plugin_instances: + pgn_inst.pre_execute() + + def call_post_execute(self): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_execute() + + def call_add_args(self, parser): + for pgn_inst in self.plugin_instances: + parser = pgn_inst.add_args(parser) + return parser + + def call_check_args(self, args, remaining): + for pgn_inst in self.plugin_instances: + pgn_inst.check_args(args, remaining) + + def call_adjust_command(self, stage, command): + for pgn_inst in self.plugin_instances: + command = pgn_inst.adjust_command(stage, command) + return command + + @staticmethod + def _make_argparser(args): + self.argparser = argparse.ArgumentParser( + description='Linux TC unit tests') + def replace_keywords(cmd): """ @@ -33,21 +107,27 @@ def replace_keywords(cmd): return subcmd -def exec_cmd(command, nsonly=True): +def exec_cmd(args, pm, stage, command, nsonly=True): """ Perform any required modifications on an executable command, then run it in a subprocess and return the results. """ + if len(command.strip()) == 0: + return None, None if (USE_NS and nsonly): command = 'ip netns exec $NS ' + command if '$' in command: command = replace_keywords(command) + command = pm.call_adjust_command(stage, command) + if args.verbose > 0: + print('command "{}"'.format(command)) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + env=ENVIR) (rawout, serr) = proc.communicate() if proc.returncode != 0 and len(serr) > 0: @@ -60,69 +140,85 @@ def exec_cmd(command, nsonly=True): return proc, foutput -def prepare_env(cmdlist): +def prepare_env(args, pm, stage, prefix, cmdlist): """ - Execute the setup/teardown commands for a test case. Optionally - terminate test execution if the command fails. + Execute the setup/teardown commands for a test case. + Optionally terminate test execution if the command fails. """ + if args.verbose > 0: + print('{}'.format(prefix)) for cmdinfo in cmdlist: - if (type(cmdinfo) == list): + if isinstance(cmdinfo, list): exit_codes = cmdinfo[1:] cmd = cmdinfo[0] else: exit_codes = [0] cmd = cmdinfo - if (len(cmd) == 0): + if not cmd: continue - (proc, foutput) = exec_cmd(cmd) + (proc, foutput) = exec_cmd(args, pm, stage, cmd) - if proc.returncode not in exit_codes: - print - print("Could not execute:") - print(cmd) - print("\nError message:") - print(foutput) - print("\nAborting test run.") - # ns_destroy() - raise Exception('prepare_env did not complete successfully') + if proc and (proc.returncode not in exit_codes): + print('', file=sys.stderr) + print("{} *** Could not execute: \"{}\"".format(prefix, cmd), + file=sys.stderr) + print("\n{} *** Error message: \"{}\"".format(prefix, foutput), + file=sys.stderr) + print("\n{} *** Aborting test run.".format(prefix), file=sys.stderr) + print("\n\n{} *** stdout ***".format(proc.stdout), file=sys.stderr) + print("\n\n{} *** stderr ***".format(proc.stderr), file=sys.stderr) + raise Exception('"{}" did not complete successfully'.format(prefix)) -def run_one_test(index, tidx): +def run_one_test(pm, args, index, tidx): result = True tresult = "" tap = "" + if args.verbose > 0: + print("\t====================\n=====> ", end="") print("Test " + tidx["id"] + ": " + tidx["name"]) - prepare_env(tidx["setup"]) - (p, procout) = exec_cmd(tidx["cmdUnderTest"]) + + pm.call_pre_case(index, tidx['id']) + prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"]) + + if (args.verbose > 0): + print('-----> execute stage') + pm.call_pre_execute() + (p, procout) = exec_cmd(args, pm, 'execute', tidx["cmdUnderTest"]) exit_code = p.returncode + pm.call_post_execute() if (exit_code != int(tidx["expExitCode"])): result = False print("exit:", exit_code, int(tidx["expExitCode"])) print(procout) else: - match_pattern = re.compile(str(tidx["matchPattern"]), - re.DOTALL | re.MULTILINE) - (p, procout) = exec_cmd(tidx["verifyCmd"]) + if args.verbose > 0: + print('-----> verify stage') + match_pattern = re.compile( + str(tidx["matchPattern"]), re.DOTALL | re.MULTILINE) + (p, procout) = exec_cmd(args, pm, 'verify', tidx["verifyCmd"]) match_index = re.findall(match_pattern, procout) if len(match_index) != int(tidx["matchCount"]): result = False if not result: - tresult += "not " - tresult += "ok {} - {} # {}\n".format(str(index), tidx['id'], tidx["name"]) + tresult += 'not ' + tresult += 'ok {} - {} # {}\n'.format(str(index), tidx['id'], tidx['name']) tap += tresult if result == False: tap += procout - prepare_env(tidx["teardown"]) + prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown']) + pm.call_post_case() + index += 1 return tap -def test_runner(filtered_tests, args): +def test_runner(pm, args, filtered_tests): """ Driver function for the unit tests. @@ -135,63 +231,71 @@ def test_runner(filtered_tests, args): tcount = len(testlist) index = 1 tap = str(index) + ".." + str(tcount) + "\n" + badtest = None + pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) + + if args.verbose > 1: + print('Run tests here') for tidx in testlist: if "flower" in tidx["category"] and args.device == None: continue try: badtest = tidx # in case it goes bad - tap += run_one_test(index, tidx) + tap += run_one_test(pm, args, index, tidx) except Exception as ee: print('Exception {} (caught in test_runner, running test {} {} {})'. format(ee, index, tidx['id'], tidx['name'])) break index += 1 + # if we failed in setup or teardown, + # fill in the remaining tests with not ok count = index tap += 'about to flush the tap output if tests need to be skipped\n' if tcount + 1 != index: for tidx in testlist[index - 1:]: msg = 'skipped - previous setup or teardown failed' - tap += 'ok {} - {} # {} {} {} \n'.format( + tap += 'ok {} - {} # {} {} {}\n'.format( count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) count += 1 tap += 'done flushing skipped test tap output\n' + pm.call_post_suite(index) return tap -def ns_create(): +def ns_create(args, pm): """ Create the network namespace in which the tests will be run and set up the required network devices for it. """ if (USE_NS): cmd = 'ip netns add $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link add $DEV0 type veth peer name $DEV1' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV1 netns $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV0 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip -n $NS link set $DEV1 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV2 netns $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip -n $NS link set $DEV2 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) -def ns_destroy(): +def ns_destroy(args, pm): """ Destroy the network namespace for testing (and any associated network devices as well) """ if (USE_NS): cmd = 'ip netns delete $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'post', cmd, False) def has_blank_ids(idlist): @@ -272,10 +376,10 @@ def set_args(parser): return parser -def check_default_settings(args): +def check_default_settings(args, remaining, pm): """ - Process any arguments overriding the default settings, and ensure the - settings are correct. + Process any arguments overriding the default settings, + and ensure the settings are correct. """ # Allow for overriding specific settings global NAMES @@ -288,6 +392,8 @@ def check_default_settings(args): print("The specified tc path " + NAMES['TC'] + " does not exist.") exit(1) + pm.call_check_args(args, remaining) + def get_id_list(alltests): """ @@ -301,16 +407,7 @@ def check_case_id(alltests): Check for duplicate test case IDs. """ idl = get_id_list(alltests) - # print('check_case_id: idl is {}'.format(idl)) - # answer = list() - # for x in idl: - # print('Looking at {}'.format(x)) - # print('what the heck is idl.count(x)??? {}'.format(idl.count(x))) - # if idl.count(x) > 1: - # answer.append(x) - # print(' ... append it {}'.format(x)) return [x for x in idl if idl.count(x) > 1] - return answer def does_id_exist(alltests, newid): @@ -403,7 +500,7 @@ def get_test_cases(args): for ff in args.file: if not os.path.isfile(ff): - print("IGNORING file " + ff + " \n\tBECAUSE does not exist.") + print("IGNORING file " + ff + "\n\tBECAUSE does not exist.") else: flist.append(os.path.abspath(ff)) @@ -445,7 +542,7 @@ def get_test_cases(args): return allcatlist, allidlist, testcases_by_cats, alltestcases -def set_operation_mode(args): +def set_operation_mode(pm, args): """ Load the test case data and process remaining arguments to determine what the script should do for this run, and call the appropriate @@ -486,12 +583,15 @@ def set_operation_mode(args): print("This script must be run with root privileges.\n") exit(1) - ns_create() + ns_create(args, pm) - catresults = test_runner(alltests, args) + if len(alltests): + catresults = test_runner(pm, args, alltests) + else: + catresults = 'No tests found\n' print('All test results: \n\n{}'.format(catresults)) - ns_destroy() + ns_destroy(args, pm) def main(): @@ -501,10 +601,15 @@ def main(): """ parser = args_parse() parser = set_args(parser) + pm = PluginMgr(parser) + parser = pm.call_add_args(parser) (args, remaining) = parser.parse_known_args() - check_default_settings(args) + args.NAMES = NAMES + check_default_settings(args, remaining, pm) + if args.verbose > 2: + print('args is {}'.format(args)) - set_operation_mode(args) + set_operation_mode(pm, args) exit(0) -- cgit v1.2.3 From f6926e85eee9be08d05170af3a2266b8d7f9cdef Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:22 -0500 Subject: tools: tc-testing: rootPlugin Move the functionality that checks for root permissions into a plugin. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../selftests/tc-testing/plugin-lib/rootPlugin.py | 19 +++++++++++++++++++ tools/testing/selftests/tc-testing/tdc.py | 4 ---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py new file mode 100644 index 000000000000..e36775bd4d12 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py @@ -0,0 +1,19 @@ +import os +import sys +from TdcPlugin import TdcPlugin + +from tdc_config import * + + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'root/SubPlugin' + super().__init__() + + def pre_suite(self, testcount, testidlist): + # run commands before test_runner goes into a test loop + super().pre_suite(testcount, testidlist) + + if os.geteuid(): + print('This script must be run with root privileges', file=sys.stderr) + exit(1) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 3e6f9f2e1691..a718d2b57739 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -579,10 +579,6 @@ def set_operation_mode(pm, args): list_test_cases(alltests) exit(0) - if (os.geteuid() != 0): - print("This script must be run with root privileges.\n") - exit(1) - ns_create(args, pm) if len(alltests): -- cgit v1.2.3 From a13fedbe56fef141aff7d584eba2a08daaf613cc Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:23 -0500 Subject: tools: tc-testing: nsPlugin Move the functionality of creating a namespace before the test suite and destroying it afterwards to a plugin. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../selftests/tc-testing/plugin-lib/nsPlugin.py | 141 +++++++++++++++++++++ tools/testing/selftests/tc-testing/tdc.py | 45 +------ 2 files changed, 142 insertions(+), 44 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py new file mode 100644 index 000000000000..a194b1af2b30 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -0,0 +1,141 @@ +import os +import signal +from string import Template +import subprocess +import time +from TdcPlugin import TdcPlugin + +from tdc_config import * + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'ns/SubPlugin' + super().__init__() + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + super().pre_suite(testcount, testidlist) + + if self.args.namespace: + self._ns_create() + + def post_suite(self, index): + '''run commands after test_runner goes into a test loop''' + super().post_suite(index) + if self.args.verbose: + print('{}.post_suite'.format(self.sub_class)) + + if self.args.namespace: + self._ns_destroy() + + def add_args(self, parser): + super().add_args(parser) + self.argparser_group = self.argparser.add_argument_group( + 'netns', + 'options for nsPlugin(run commands in net namespace)') + self.argparser_group.add_argument( + '-n', '--namespace', action='store_true', + help='Run commands in namespace') + return self.argparser + + def adjust_command(self, stage, command): + super().adjust_command(stage, command) + cmdform = 'list' + cmdlist = list() + + if not self.args.namespace: + return command + + if self.args.verbose: + print('{}.adjust_command'.format(self.sub_class)) + + if not isinstance(command, list): + cmdform = 'str' + cmdlist = command.split() + else: + cmdlist = command + if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown': + if self.args.verbose: + print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist)) + cmdlist.insert(0, self.args.NAMES['NS']) + cmdlist.insert(0, 'exec') + cmdlist.insert(0, 'netns') + cmdlist.insert(0, 'ip') + else: + pass + + if cmdform == 'str': + command = ' '.join(cmdlist) + else: + command = cmdlist + + if self.args.verbose: + print('adjust_command: return command [{}]'.format(command)) + return command + + def _ns_create(self): + ''' + Create the network namespace in which the tests will be run and set up + the required network devices for it. + ''' + if self.args.namespace: + cmd = 'ip netns add {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip link add $DEV0 type veth peer name $DEV1' + self._exec_cmd('pre', cmd) + cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip link set $DEV0 up' + self._exec_cmd('pre', cmd) + cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + if self.args.device: + cmd = 'ip link set $DEV2 netns {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip -n {} link set $DEV2 up'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + + def _ns_destroy(self): + ''' + Destroy the network namespace for testing (and any associated network + devices as well) + ''' + if self.args.namespace: + cmd = 'ip netns delete {}'.format(self.args.NAMES['NS']) + self._exec_cmd('post', cmd) + + def _exec_cmd(self, stage, command): + ''' + Perform any required modifications on an executable command, then run + it in a subprocess and return the results. + ''' + if '$' in command: + command = self._replace_keywords(command) + + self.adjust_command(stage, command) + if self.args.verbose: + print('_exec_cmd: command "{}"'.format(command)) + proc = subprocess.Popen(command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=ENVIR) + (rawout, serr) = proc.communicate() + + if proc.returncode != 0 and len(serr) > 0: + foutput = serr.decode("utf-8") + else: + foutput = rawout.decode("utf-8") + + proc.stdout.close() + proc.stderr.close() + return proc, foutput + + def _replace_keywords(self, cmd): + """ + For a given executable command, substitute any known + variables contained within NAMES with the correct values + """ + tcmd = Template(cmd) + subcmd = tcmd.safe_substitute(self.args.NAMES) + return subcmd diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index a718d2b57739..b3754b9aa302 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -23,8 +23,6 @@ from tdc_helper import * import TdcPlugin -USE_NS = True - class PluginMgr: def __init__(self, argparser): super().__init__() @@ -107,16 +105,13 @@ def replace_keywords(cmd): return subcmd -def exec_cmd(args, pm, stage, command, nsonly=True): +def exec_cmd(args, pm, stage, command): """ Perform any required modifications on an executable command, then run it in a subprocess and return the results. """ if len(command.strip()) == 0: return None, None - if (USE_NS and nsonly): - command = 'ip netns exec $NS ' + command - if '$' in command: command = replace_keywords(command) @@ -265,39 +260,6 @@ def test_runner(pm, args, filtered_tests): return tap - -def ns_create(args, pm): - """ - Create the network namespace in which the tests will be run and set up - the required network devices for it. - """ - if (USE_NS): - cmd = 'ip netns add $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link add $DEV0 type veth peer name $DEV1' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV1 netns $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV0 up' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip -n $NS link set $DEV1 up' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV2 netns $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip -n $NS link set $DEV2 up' - exec_cmd(args, pm, 'pre', cmd, False) - - -def ns_destroy(args, pm): - """ - Destroy the network namespace for testing (and any associated network - devices as well) - """ - if (USE_NS): - cmd = 'ip netns delete $NS' - exec_cmd(args, pm, 'post', cmd, False) - - def has_blank_ids(idlist): """ Search the list for empty ID fields and return true/false accordingly. @@ -579,17 +541,12 @@ def set_operation_mode(pm, args): list_test_cases(alltests) exit(0) - ns_create(args, pm) - if len(alltests): catresults = test_runner(pm, args, alltests) else: catresults = 'No tests found\n' print('All test results: \n\n{}'.format(catresults)) - ns_destroy(args, pm) - - def main(): """ Start of execution; set up argument parser and get the arguments, -- cgit v1.2.3 From c25e4736867f73901de4fdb62c122ae2c6d91159 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:24 -0500 Subject: tools: tc-testing: valgrindPlugin Run the command under test under valgrind. Produce an extra set of tap output for the memory check on each test. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../tc-testing/plugin-lib/valgrindPlugin.py | 142 +++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py new file mode 100644 index 000000000000..477a7bd7d7fb --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py @@ -0,0 +1,142 @@ +''' +run the command under test, under valgrind and collect memory leak info +as a separate test. +''' + + +import os +import re +import signal +from string import Template +import subprocess +import time +from TdcPlugin import TdcPlugin + +from tdc_config import * + +def vp_extract_num_from_string(num_as_string_maybe_with_commas): + return int(num_as_string_maybe_with_commas.replace(',','')) + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'valgrind/SubPlugin' + self.tap = '' + super().__init__() + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + super().pre_suite(testcount, testidlist) + if self.args.verbose > 1: + print('{}.pre_suite'.format(self.sub_class)) + if self.args.valgrind: + self._add_to_tap('1..{}\n'.format(self.testcount)) + + def post_suite(self, index): + '''run commands after test_runner goes into a test loop''' + super().post_suite(index) + self._add_to_tap('\n|---\n') + if self.args.verbose > 1: + print('{}.post_suite'.format(self.sub_class)) + print('{}'.format(self.tap)) + if self.args.verbose < 4: + subprocess.check_output('rm -f vgnd-*.log', shell=True) + + def add_args(self, parser): + super().add_args(parser) + self.argparser_group = self.argparser.add_argument_group( + 'valgrind', + 'options for valgrindPlugin (run command under test under Valgrind)') + + self.argparser_group.add_argument( + '-V', '--valgrind', action='store_true', + help='Run commands under valgrind') + + return self.argparser + + def adjust_command(self, stage, command): + super().adjust_command(stage, command) + cmdform = 'list' + cmdlist = list() + + if not self.args.valgrind: + return command + + if self.args.verbose > 1: + print('{}.adjust_command'.format(self.sub_class)) + + if not isinstance(command, list): + cmdform = 'str' + cmdlist = command.split() + else: + cmdlist = command + + if stage == 'execute': + if self.args.verbose > 1: + print('adjust_command: stage is {}; inserting valgrind stuff in command [{}] list [{}]'. + format(stage, command, cmdlist)) + cmdlist.insert(0, '--track-origins=yes') + cmdlist.insert(0, '--show-leak-kinds=definite,indirect') + cmdlist.insert(0, '--leak-check=full') + cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid)) + cmdlist.insert(0, '-v') # ask for summary of non-leak errors + cmdlist.insert(0, ENVIR['VALGRIND_BIN']) + else: + pass + + if cmdform == 'str': + command = ' '.join(cmdlist) + else: + command = cmdlist + + if self.args.verbose > 1: + print('adjust_command: return command [{}]'.format(command)) + return command + + def post_execute(self): + if not self.args.valgrind: + return + + self.definitely_lost_re = re.compile( + r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL) + self.indirectly_lost_re = re.compile( + r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) + self.possibly_lost_re = re.compile( + r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) + self.non_leak_error_re = re.compile( + r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL) + + def_num = 0 + ind_num = 0 + pos_num = 0 + nle_num = 0 + + # what about concurrent test runs? Maybe force them to be in different directories? + with open('vgnd-{}.log'.format(self.args.testid)) as vfd: + content = vfd.read() + def_mo = self.definitely_lost_re.search(content) + ind_mo = self.indirectly_lost_re.search(content) + pos_mo = self.possibly_lost_re.search(content) + nle_mo = self.non_leak_error_re.search(content) + + if def_mo: + def_num = int(def_mo.group(2)) + if ind_mo: + ind_num = int(ind_mo.group(2)) + if pos_mo: + pos_num = int(pos_mo.group(2)) + if nle_mo: + nle_num = int(nle_mo.group(1)) + + mem_results = '' + if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0): + mem_results += 'not ' + + mem_results += 'ok {} - {}-mem # {}\n'.format( + self.args.test_ordinal, self.args.testid, 'memory leak check') + self._add_to_tap(mem_results) + if mem_results.startswith('not '): + print('{}'.format(content)) + self._add_to_tap(content) + + def _add_to_tap(self, more_tap_output): + self.tap += more_tap_output -- cgit v1.2.3 From 95ce14c3fff87ee43366c8cf84790f2e72167633 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:25 -0500 Subject: tools: tc-testing: Update README and TODO Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/README | 173 +++++++++++++++++++++++++--- tools/testing/selftests/tc-testing/TODO.txt | 25 +++- 2 files changed, 179 insertions(+), 19 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 970ff294fec8..3a0336782d2d 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -14,11 +14,11 @@ REQUIREMENTS * The kernel must have network namespace support -* The kernel must have veth support available, as a veth pair is created +* The kernel must have veth support available, as a veth pair is created prior to running the tests. -* All tc-related features must be built in or available as modules. - To check what is required in current setup run: +* All tc-related features being tested must be built in or available as + modules. To check what is required in current setup run: ./tdc.py -c Note: @@ -44,10 +44,13 @@ using the -p option when running tdc: RUNNING TDC ----------- -To use tdc, root privileges are required. tdc will not run otherwise. +To use tdc, root privileges are required. This is because the +commands being tested must be run as root. The code that enforces +execution by root uid has been moved into a plugin (see PLUGIN +ARCHITECTURE, below). -All tests are executed inside a network namespace to prevent conflicts -within the host. +If nsPlugin is linked, all tests are executed inside a network +namespace to prevent conflicts within the host. Running tdc without any arguments will run all tests. Refer to the section on command line arguments for more information, or run: @@ -59,6 +62,33 @@ output captured from the failing test will be printed immediately following the failed test in the TAP output. +OVERVIEW OF TDC EXECUTION +------------------------- + +One run of tests is considered a "test suite" (this will be refined in the +future). A test suite has one or more test cases in it. + +A test case has four stages: + + - setup + - execute + - verify + - teardown + +The setup and teardown stages can run zero or more commands. The setup +stage does some setup if the test needs it. The teardown stage undoes +the setup and returns the system to a "neutral" state so any other test +can be run next. These two stages require any commands run to return +success, but do not otherwise verify the results. + +The execute and verify stages each run one command. The execute stage +tests the return code against one or more acceptable values. The +verify stage checks the return code for success, and also compares +the stdout with a regular expression. + +Each of the commands in any stage will run in a shell instance. + + USER-DEFINED CONSTANTS ---------------------- @@ -70,23 +100,132 @@ executed as part of the test. More will be added as test cases require. Example: $TC qdisc add dev $DEV1 ingress +The NAMES values are used to substitute into the commands in the test cases. + COMMAND LINE ARGUMENTS ---------------------- Run tdc.py -h to see the full list of available arguments. --p PATH Specify the tc executable located at PATH to be used on this - test run --c Show the available test case categories in this test file --c CATEGORY Run only tests that belong to CATEGORY --f FILE Read test cases from the JSON file named FILE --l [CATEGORY] List all test cases in the JSON file. If CATEGORY is - specified, list test cases matching that category. --s ID Show the test case matching ID --e ID Execute the test case identified by ID --i Generate unique ID numbers for test cases with no existing - ID number +usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]] + [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] + [-d DEVICE] [-n NS] [-V] + +Linux TC unit tests + +optional arguments: + -h, --help show this help message and exit + -p PATH, --path PATH The full path to the tc executable to use + -v, --verbose Show the commands that are being run + -d DEVICE, --device DEVICE + Execute the test case in flower category + +selection: + select which test cases: files plus directories; filtered by categories + plus testids + + -D DIR [DIR ...], --directory DIR [DIR ...] + Collect tests from the specified directory(ies) + (default [tc-tests]) + -f FILE [FILE ...], --file FILE [FILE ...] + Run tests from the specified file(s) + -c [CATG [CATG ...]], --category [CATG [CATG ...]] + Run tests only from the specified category/ies, or if + no category/ies is/are specified, list known + categories. + -e ID [ID ...], --execute ID [ID ...] + Execute the specified test cases with specified IDs + +action: + select action to perform on selected test cases + + -l, --list List all test cases, or those only within the + specified category + -s, --show Display the selected test cases + -i, --id Generate ID numbers for new test cases + +netns: + options for nsPlugin(run commands in net namespace) + + -n NS, --namespace NS + Run commands in namespace NS + +valgrind: + options for valgrindPlugin (run command under test under Valgrind) + + -V, --valgrind Run commands under valgrind + + +PLUGIN ARCHITECTURE +------------------- + +There is now a plugin architecture, and some of the functionality that +was in the tdc.py script has been moved into the plugins. + +The plugins are in the directory plugin-lib. The are executed from +directory plugins. Put symbolic links from plugins to plugin-lib, +and name them according to the order you want them to run. + +Example: + +bjb@bee:~/work/tc-testing$ ls -l plugins +total 4 +lrwxrwxrwx 1 bjb bjb 27 Oct 4 16:12 10-rootPlugin.py -> ../plugin-lib/rootPlugin.py +lrwxrwxrwx 1 bjb bjb 25 Oct 12 17:55 20-nsPlugin.py -> ../plugin-lib/nsPlugin.py +-rwxr-xr-x 1 bjb bjb 0 Sep 29 15:56 __init__.py + +The plugins are a subclass of TdcPlugin, defined in TdcPlugin.py and +must be called "SubPlugin" so tdc can find them. They are +distinguished from each other in the python program by their module +name. + +This base class supplies "hooks" to run extra functions. These hooks are as follows: + +pre- and post-suite +pre- and post-case +pre- and post-execute stage +adjust-command (runs in all stages and receives the stage name) + +The pre-suite hook receives the number of tests and an array of test ids. +This allows you to dump out the list of skipped tests in the event of a +failure during setup or teardown stage. + +The pre-case hook receives the ordinal number and test id of the current test. + +The adjust-command hook receives the stage id (see list below) and the +full command to be executed. This allows for last-minute adjustment +of the command. + +The stages are identified by the following strings: + + - pre (pre-suite) + - setup + - command + - verify + - teardown + - post (post-suite) + + +To write a plugin, you need to inherit from TdcPlugin in +TdcPlugin.py. To use the plugin, you have to put the +implementation file in plugin-lib, and add a symbolic link to it from +plugins. It will be detected at run time and invoked at the +appropriate times. There are a few examples in the plugin-lib +directory: + + - rootPlugin.py: + implements the enforcement of running as root + - nsPlugin.py: + sets up a network namespace and runs all commands in that namespace + - valgrindPlugin.py + runs each command in the execute stage under valgrind, + and checks for leaks. + This plugin will output an extra test for each test in the test file, + one is the existing output as to whether the test passed or failed, + and the other is a test whether the command leaked memory or not. + (This one is a preliminary version, it may not work quite right yet, + but the overall template is there and it should only need tweaks.) ACKNOWLEDGEMENTS diff --git a/tools/testing/selftests/tc-testing/TODO.txt b/tools/testing/selftests/tc-testing/TODO.txt index 6a266d811a78..c40698557e2f 100644 --- a/tools/testing/selftests/tc-testing/TODO.txt +++ b/tools/testing/selftests/tc-testing/TODO.txt @@ -5,6 +5,27 @@ tc Testing Suite To-Do list: - Add support for multiple versions of tc to run successively -- Improve error messages when tdc aborts its run +- Improve error messages when tdc aborts its run. Partially done - still + need to better handle problems in pre- and post-suite. -- Allow tdc to write its results to file +- Use python logger module for debug/verbose output + +- Allow tdc to write its results to file. + Maybe use python logger module for this too. + +- A better implementation of the "hooks". Currently, every plugin + will attempt to run a function at every hook point. Could be + changed so that plugin __init__ methods will register functions to + be run in the various predefined times. Then if a plugin does not + require action at a specific point, no penalty will be paid for + trying to run a function that will do nothing. + +- Proper exception handling - make an exception class and use it + +- a TestCase class, for easier testcase handling, searching, comparison + +- a TestSuite class + and a way to configure a test suite, + to automate running multiple "test suites" with different requirements + +- super simple test case example using ls, touch, etc -- cgit v1.2.3 From ddd0010392d9cbcb95b53d11b7cafc67b373ab56 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Thu, 15 Feb 2018 09:19:26 +0900 Subject: selftests/net: fixes psock_fanout eBPF test case eBPF test fails due to verifier failure because log_buf is too small. Fixed by increasing log_buf size Signed-off-by: Prashant Bhole Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/psock_fanout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index 989f917068d1..d4346b16b2c1 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -128,6 +128,8 @@ static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id) static void sock_fanout_set_ebpf(int fd) { + static char log_buf[65536]; + const int len_off = __builtin_offsetof(struct __sk_buff, len); struct bpf_insn prog[] = { { BPF_ALU64 | BPF_MOV | BPF_X, 6, 1, 0, 0 }, @@ -140,7 +142,6 @@ static void sock_fanout_set_ebpf(int fd) { BPF_ALU | BPF_MOV | BPF_K, 0, 0, 0, 0 }, { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 } }; - char log_buf[512]; union bpf_attr attr; int pfd; -- cgit v1.2.3 From b16ac920403e5623150e428e7f5429e8eb607308 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 15 Feb 2018 10:49:37 -0800 Subject: selftests/net: add support for PF_RDS sockets Add support for basic PF_RDS client-server testing in msg_zerocopy Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 65 +++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index e11fe84de0fd..7a5b35362f84 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -14,6 +14,9 @@ * - SOCK_DGRAM * - SOCK_RAW * + * PF_RDS + * - SOCK_SEQPACKET + * * Start this program on two connected hosts, one in send mode and * the other with option '-r' to put it in receiver mode. * @@ -53,6 +56,7 @@ #include #include #include +#include #ifndef SO_EE_ORIGIN_ZEROCOPY #define SO_EE_ORIGIN_ZEROCOPY 5 @@ -300,10 +304,15 @@ static int do_setup_tx(int domain, int type, int protocol) if (cfg_zerocopy) do_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, 1); - if (domain != PF_PACKET) + if (domain != PF_PACKET && domain != PF_RDS) if (connect(fd, (void *) &cfg_dst_addr, cfg_alen)) error(1, errno, "connect"); + if (domain == PF_RDS) { + if (bind(fd, (void *) &cfg_src_addr, cfg_alen)) + error(1, errno, "bind"); + } + return fd; } @@ -444,6 +453,13 @@ static void do_tx(int domain, int type, int protocol) msg.msg_iovlen++; } + if (domain == PF_RDS) { + msg.msg_name = &cfg_dst_addr; + msg.msg_namelen = (cfg_dst_addr.ss_family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + } + iov[2].iov_base = payload; iov[2].iov_len = cfg_payload_len; msg.msg_iovlen++; @@ -555,6 +571,40 @@ static void do_flush_datagram(int fd, int type) bytes += cfg_payload_len; } + +static void do_recvmsg(int fd) +{ + int ret, off = 0; + char *buf; + struct iovec iov; + struct msghdr msg; + struct sockaddr_storage din; + + buf = calloc(cfg_payload_len, sizeof(char)); + iov.iov_base = buf; + iov.iov_len = cfg_payload_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &din; + msg.msg_namelen = sizeof(din); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ret = recvmsg(fd, &msg, MSG_TRUNC); + + if (ret == -1) + error(1, errno, "recv"); + if (ret != cfg_payload_len) + error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); + + if (memcmp(buf + off, payload, ret)) + error(1, 0, "recv: data mismatch"); + + free(buf); + packets++; + bytes += cfg_payload_len; +} + static void do_rx(int domain, int type, int protocol) { uint64_t tstop; @@ -566,6 +616,8 @@ static void do_rx(int domain, int type, int protocol) do { if (type == SOCK_STREAM) do_flush_tcp(fd); + else if (domain == PF_RDS) + do_recvmsg(fd); else do_flush_datagram(fd, type); @@ -610,6 +662,7 @@ static void parse_opts(int argc, char **argv) 40 /* max tcp options */; int c; char *daddr = NULL, *saddr = NULL; + char *cfg_test; cfg_payload_len = max_payload_len; @@ -667,6 +720,14 @@ static void parse_opts(int argc, char **argv) break; } } + + cfg_test = argv[argc - 1]; + if (strcmp(cfg_test, "rds") == 0) { + if (!daddr) + error(1, 0, "-D required for PF_RDS\n"); + if (!cfg_rx && !saddr) + error(1, 0, "-S required for PF_RDS\n"); + } setup_sockaddr(cfg_family, daddr, &cfg_dst_addr); setup_sockaddr(cfg_family, saddr, &cfg_src_addr); @@ -699,6 +760,8 @@ int main(int argc, char **argv) do_test(cfg_family, SOCK_STREAM, 0); else if (!strcmp(cfg_test, "udp")) do_test(cfg_family, SOCK_DGRAM, 0); + else if (!strcmp(cfg_test, "rds")) + do_test(PF_RDS, SOCK_SEQPACKET, 0); else error(1, 0, "unknown cfg_test %s", cfg_test); -- cgit v1.2.3 From dfb8434b0a94651dac7adf373900561d8f6499e4 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 15 Feb 2018 10:49:38 -0800 Subject: selftests/net: add zerocopy support for PF_RDS test case Send a cookie with sendmsg() on PF_RDS sockets, and process the returned batched cookies in do_recv_completion() Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 68 ++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 7a5b35362f84..5cc2a53bb71c 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -168,17 +168,39 @@ static int do_accept(int fd) return fd; } -static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy) +static void add_zcopy_cookie(struct msghdr *msg, uint32_t cookie) +{ + struct cmsghdr *cm; + + if (!msg->msg_control) + error(1, errno, "NULL cookie"); + cm = (void *)msg->msg_control; + cm->cmsg_len = CMSG_LEN(sizeof(cookie)); + cm->cmsg_level = SOL_RDS; + cm->cmsg_type = RDS_CMSG_ZCOPY_COOKIE; + memcpy(CMSG_DATA(cm), &cookie, sizeof(cookie)); +} + +static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy, int domain) { int ret, len, i, flags; + static uint32_t cookie; + char ckbuf[CMSG_SPACE(sizeof(cookie))]; len = 0; for (i = 0; i < msg->msg_iovlen; i++) len += msg->msg_iov[i].iov_len; flags = MSG_DONTWAIT; - if (do_zerocopy) + if (do_zerocopy) { flags |= MSG_ZEROCOPY; + if (domain == PF_RDS) { + memset(&msg->msg_control, 0, sizeof(msg->msg_control)); + msg->msg_controllen = CMSG_SPACE(sizeof(cookie)); + msg->msg_control = (struct cmsghdr *)ckbuf; + add_zcopy_cookie(msg, ++cookie); + } + } ret = sendmsg(fd, msg, flags); if (ret == -1 && errno == EAGAIN) @@ -194,6 +216,10 @@ static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy) if (do_zerocopy && ret) expected_completions++; } + if (do_zerocopy && domain == PF_RDS) { + msg->msg_control = NULL; + msg->msg_controllen = 0; + } return true; } @@ -220,7 +246,9 @@ static void do_sendmsg_corked(int fd, struct msghdr *msg) msg->msg_iov[0].iov_len = payload_len + extra_len; extra_len = 0; - do_sendmsg(fd, msg, do_zerocopy); + do_sendmsg(fd, msg, do_zerocopy, + (cfg_dst_addr.ss_family == AF_INET ? + PF_INET : PF_INET6)); } do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0); @@ -316,6 +344,26 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } +static int do_process_zerocopy_cookies(struct sock_extended_err *serr, + uint32_t *ckbuf, size_t nbytes) +{ + int ncookies, i; + + if (serr->ee_errno != 0) + error(1, 0, "serr: wrong error code: %u", serr->ee_errno); + ncookies = serr->ee_data; + if (ncookies > SO_EE_ORIGIN_MAX_ZCOOKIES) + error(1, 0, "Returned %d cookies, max expected %d\n", + ncookies, SO_EE_ORIGIN_MAX_ZCOOKIES); + if (nbytes != ncookies * sizeof(uint32_t)) + error(1, 0, "Expected %d cookies, got %ld\n", + ncookies, nbytes/sizeof(uint32_t)); + for (i = 0; i < ncookies; i++) + if (cfg_verbose >= 2) + fprintf(stderr, "%d\n", ckbuf[i]); + return ncookies; +} + static bool do_recv_completion(int fd) { struct sock_extended_err *serr; @@ -324,10 +372,17 @@ static bool do_recv_completion(int fd) uint32_t hi, lo, range; int ret, zerocopy; char control[100]; + uint32_t ckbuf[SO_EE_ORIGIN_MAX_ZCOOKIES]; + struct iovec iov; msg.msg_control = control; msg.msg_controllen = sizeof(control); + iov.iov_base = ckbuf; + iov.iov_len = (SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(ckbuf[0])); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + ret = recvmsg(fd, &msg, MSG_ERRQUEUE); if (ret == -1 && errno == EAGAIN) return false; @@ -346,6 +401,11 @@ static bool do_recv_completion(int fd) cm->cmsg_level, cm->cmsg_type); serr = (void *) CMSG_DATA(cm); + + if (serr->ee_origin == SO_EE_ORIGIN_ZCOOKIE) { + completions += do_process_zerocopy_cookies(serr, ckbuf, ret); + return true; + } if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) error(1, 0, "serr: wrong origin: %u", serr->ee_origin); if (serr->ee_errno != 0) @@ -470,7 +530,7 @@ static void do_tx(int domain, int type, int protocol) if (cfg_cork) do_sendmsg_corked(fd, &msg); else - do_sendmsg(fd, &msg, cfg_zerocopy); + do_sendmsg(fd, &msg, cfg_zerocopy, domain); while (!do_poll(fd, POLLOUT)) { if (cfg_zerocopy) -- cgit v1.2.3 From cc30c93fa020e13c91f5076e20062df33f944cdc Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 23 Feb 2018 11:56:20 -0500 Subject: selftests/net: ignore background traffic in psock_fanout The packet fanout test generates UDP traffic and reads this with a pair of packet sockets, testing the various fanout algorithms. Avoid non-determinism from reading unrelated background traffic. Fanout decisions are made before unrelated packets can be dropped with a filter, so that is an insufficient strategy [*]. Run the packet socket tests in a network namespace, similar to msg_zerocopy. It it still good practice to install a filter on a packet socket before accepting traffic. Because this is example code, demonstrate that pattern. Open the socket initially bound to no protocol, install a filter, and only then bind to ETH_P_IP. Another source of non-determinism is hash collisions in FANOUT_HASH. The hash function used to select a socket in the fanout group includes the pseudorandom number hashrnd, which is not visible from userspace. To work around this, the test tries to find a pair of UDP source ports that do not collide. It gives up too soon (5 times, every 32 runs) and output is confusing. Increase tries to 20 and revise the error msg. [*] another approach would be to add a third socket to the fanout group and direct all unexpected traffic here. This is possible only when reimplementing methods like RR or HASH alongside this extra catch-all bucket, using the BPF fanout method. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/in_netns.sh | 23 +++++++++++++++++++ tools/testing/selftests/net/psock_fanout.c | 32 ++++++++++++++++++++++----- tools/testing/selftests/net/run_afpackettests | 4 ++-- 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100755 tools/testing/selftests/net/in_netns.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/in_netns.sh b/tools/testing/selftests/net/in_netns.sh new file mode 100755 index 000000000000..f57a2eaad069 --- /dev/null +++ b/tools/testing/selftests/net/in_netns.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Execute a subprocess in a network namespace + +set -e + +readonly NETNS="ns-$(mktemp -u XXXXXX)" + +setup() { + ip netns add "${NETNS}" + ip -netns "${NETNS}" link set lo up +} + +cleanup() { + ip netns del "${NETNS}" +} + +trap cleanup EXIT +setup + +"$@" +exit "$?" diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index d4346b16b2c1..bd9b9632c72b 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -73,14 +74,29 @@ * @return -1 if mode is bad, a valid socket otherwise */ static int sock_fanout_open(uint16_t typeflags, uint16_t group_id) { + struct sockaddr_ll addr = {0}; int fd, val; - fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); + fd = socket(PF_PACKET, SOCK_RAW, 0); if (fd < 0) { perror("socket packet"); exit(1); } + pair_udp_setfilter(fd); + + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_IP); + addr.sll_ifindex = if_nametoindex("lo"); + if (addr.sll_ifindex == 0) { + perror("if_nametoindex"); + exit(1); + } + if (bind(fd, (void *) &addr, sizeof(addr))) { + perror("bind packet"); + exit(1); + } + val = (((int) typeflags) << 16) | group_id; if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) { if (close(fd)) { @@ -90,7 +106,6 @@ static int sock_fanout_open(uint16_t typeflags, uint16_t group_id) return -1; } - pair_udp_setfilter(fd); return fd; } @@ -229,7 +244,7 @@ static int sock_fanout_read(int fds[], char *rings[], const int expect[]) if ((!(ret[0] == expect[0] && ret[1] == expect[1])) && (!(ret[0] == expect[1] && ret[1] == expect[0]))) { - fprintf(stderr, "ERROR: incorrect queue lengths\n"); + fprintf(stderr, "warning: incorrect queue lengths\n"); return 1; } @@ -348,7 +363,8 @@ static int test_datapath(uint16_t typeflags, int port_off, uint8_t type = typeflags & 0xFF; int fds[2], fds_udp[2][2], ret; - fprintf(stderr, "test: datapath 0x%hx\n", typeflags); + fprintf(stderr, "\ntest: datapath 0x%hx ports %hu,%hu\n", + typeflags, PORT_BASE, PORT_BASE + port_off); fds[0] = sock_fanout_open(typeflags, 0); fds[1] = sock_fanout_open(typeflags, 0); @@ -419,7 +435,7 @@ int main(int argc, char **argv) const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } }; const int expect_uniqueid[2][2] = { { 20, 20}, { 20, 20 } }; - int port_off = 2, tries = 5, ret; + int port_off = 2, tries = 20, ret; test_control_single(); test_control_group(); @@ -428,10 +444,14 @@ int main(int argc, char **argv) /* find a set of ports that do not collide onto the same socket */ ret = test_datapath(PACKET_FANOUT_HASH, port_off, expect_hash[0], expect_hash[1]); - while (ret && tries--) { + while (ret) { fprintf(stderr, "info: trying alternate ports (%d)\n", tries); ret = test_datapath(PACKET_FANOUT_HASH, ++port_off, expect_hash[0], expect_hash[1]); + if (!--tries) { + fprintf(stderr, "too many collisions\n"); + return 1; + } } ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER, diff --git a/tools/testing/selftests/net/run_afpackettests b/tools/testing/selftests/net/run_afpackettests index 21fe149e3de1..bea079edc278 100755 --- a/tools/testing/selftests/net/run_afpackettests +++ b/tools/testing/selftests/net/run_afpackettests @@ -9,7 +9,7 @@ fi echo "--------------------" echo "running psock_fanout test" echo "--------------------" -./psock_fanout +./in_netns.sh ./psock_fanout if [ $? -ne 0 ]; then echo "[FAIL]" else @@ -19,7 +19,7 @@ fi echo "--------------------" echo "running psock_tpacket test" echo "--------------------" -./psock_tpacket +./in_netns.sh ./psock_tpacket if [ $? -ne 0 ]; then echo "[FAIL]" else -- cgit v1.2.3 From 23d191a82c133c31bb85aa4b4b26851cd4a4b4ac Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 24 Feb 2018 01:08:03 +0100 Subject: bpf: add various jit test cases Add few test cases that check the rnu-time results under JIT. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 2971ba2829ac..c987d3a2426f 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11140,6 +11140,95 @@ static struct bpf_test tests[] = { .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, + { + "jit: lsh, rsh, arsh by 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_MOV64_IMM(BPF_REG_1, 0xff), + BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 1), + BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0x3fc, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 1), + BPF_ALU32_IMM(BPF_RSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0xff, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_ARSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0x7f, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: mov32 for ldimm64, 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_LD_IMM64(BPF_REG_1, 0xfeffffffffffffffULL), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32), + BPF_LD_IMM64(BPF_REG_2, 0xfeffffffULL), + BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_2, 1), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: mov32 for ldimm64, 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_IMM64(BPF_REG_1, 0x1ffffffffULL), + BPF_LD_IMM64(BPF_REG_2, 0xffffffffULL), + BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_2, 1), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: various mul tests", + .insns = { + BPF_LD_IMM64(BPF_REG_2, 0xeeff0d413122ULL), + BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL), + BPF_LD_IMM64(BPF_REG_1, 0xefefefULL), + BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL), + BPF_ALU64_REG(BPF_MUL, BPF_REG_3, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV32_REG(BPF_REG_2, BPF_REG_2), + BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_0, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_3, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_0, 0x952a7bbcULL), + BPF_LD_IMM64(BPF_REG_1, 0xfefefeULL), + BPF_LD_IMM64(BPF_REG_2, 0xeeff0d413122ULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_2, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_2, BPF_REG_0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + }; static int probe_filter_length(const struct bpf_insn *fp) -- cgit v1.2.3 From 6a7b75f7c16d85f782ae86c71f0f31f72a61602f Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Fri, 23 Feb 2018 12:16:37 -0500 Subject: tools: tc-testing: Fix indentation Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index b3754b9aa302..ab28373dccd7 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -347,9 +347,9 @@ def check_default_settings(args, remaining, pm): global NAMES if args.path != None: - NAMES['TC'] = args.path + NAMES['TC'] = args.path if args.device != None: - NAMES['DEV2'] = args.device + NAMES['DEV2'] = args.device if not os.path.isfile(NAMES['TC']): print("The specified tc path " + NAMES['TC'] + " does not exist.") exit(1) -- cgit v1.2.3 From f9b63a1c91d4d2b4fcac5c786cdd7de1242c162b Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Fri, 23 Feb 2018 12:16:38 -0500 Subject: tools: tc-testing: better error reporting Do a better job with error handling - in pre- and post-suite, in pre- and post-case. Show a traceback for errors. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 84 +++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 14 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index ab28373dccd7..6c220bc26d9f 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -15,6 +15,7 @@ import importlib import json import subprocess import time +import traceback from collections import OrderedDict from string import Template @@ -23,6 +24,13 @@ from tdc_helper import * import TdcPlugin + +class PluginMgrTestFail(Exception): + def __init__(self, stage, output, message): + self.stage = stage + self.output = output + self.message = message + class PluginMgr: def __init__(self, argparser): super().__init__() @@ -135,7 +143,7 @@ def exec_cmd(args, pm, stage, command): return proc, foutput -def prepare_env(args, pm, stage, prefix, cmdlist): +def prepare_env(args, pm, stage, prefix, cmdlist, output = None): """ Execute the setup/teardown commands for a test case. Optionally terminate test execution if the command fails. @@ -164,7 +172,9 @@ def prepare_env(args, pm, stage, prefix, cmdlist): print("\n{} *** Aborting test run.".format(prefix), file=sys.stderr) print("\n\n{} *** stdout ***".format(proc.stdout), file=sys.stderr) print("\n\n{} *** stderr ***".format(proc.stderr), file=sys.stderr) - raise Exception('"{}" did not complete successfully'.format(prefix)) + raise PluginMgrTestFail( + stage, output, + '"{}" did not complete successfully'.format(prefix)) def run_one_test(pm, args, index, tidx): result = True @@ -194,8 +204,11 @@ def run_one_test(pm, args, index, tidx): match_pattern = re.compile( str(tidx["matchPattern"]), re.DOTALL | re.MULTILINE) (p, procout) = exec_cmd(args, pm, 'verify', tidx["verifyCmd"]) - match_index = re.findall(match_pattern, procout) - if len(match_index) != int(tidx["matchCount"]): + if procout: + match_index = re.findall(match_pattern, procout) + if len(match_index) != int(tidx["matchCount"]): + result = False + elif int(tidx["matchCount"]) != 0: result = False if not result: @@ -204,9 +217,12 @@ def run_one_test(pm, args, index, tidx): tap += tresult if result == False: - tap += procout + if procout: + tap += procout + else: + tap += 'No output!\n' - prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown']) + prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown'], procout) pm.call_post_case() index += 1 @@ -227,30 +243,70 @@ def test_runner(pm, args, filtered_tests): index = 1 tap = str(index) + ".." + str(tcount) + "\n" badtest = None + stage = None + emergency_exit = False + emergency_exit_message = '' - pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) - + try: + pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) + except Exception as ee: + ex_type, ex, ex_tb = sys.exc_info() + print('Exception {} {} (caught in pre_suite).'. + format(ex_type, ex)) + # when the extra print statements are uncommented, + # the traceback does not appear between them + # (it appears way earlier in the tdc.py output) + # so don't bother ... + # print('--------------------(') + # print('traceback') + traceback.print_tb(ex_tb) + # print('--------------------)') + emergency_exit_message = 'EMERGENCY EXIT, call_pre_suite failed with exception {} {}\n'.format(ex_type, ex) + emergency_exit = True + stage = 'pre-SUITE' + + if emergency_exit: + pm.call_post_suite(index) + return emergency_exit_message if args.verbose > 1: - print('Run tests here') + print('give test rig 2 seconds to stabilize') + time.sleep(2) for tidx in testlist: if "flower" in tidx["category"] and args.device == None: + if args.verbose > 1: + print('Not executing test {} {} because DEV2 not defined'. + format(tidx['id'], tidx['name'])) continue try: badtest = tidx # in case it goes bad tap += run_one_test(pm, args, index, tidx) - except Exception as ee: - print('Exception {} (caught in test_runner, running test {} {} {})'. - format(ee, index, tidx['id'], tidx['name'])) + except PluginMgrTestFail as pmtf: + ex_type, ex, ex_tb = sys.exc_info() + stage = pmtf.stage + message = pmtf.message + output = pmtf.output + print(message) + print('Exception {} {} (caught in test_runner, running test {} {} {} stage {})'. + format(ex_type, ex, index, tidx['id'], tidx['name'], stage)) + print('---------------') + print('traceback') + traceback.print_tb(ex_tb) + print('---------------') + if stage == 'teardown': + print('accumulated output for this test:') + if pmtf.output: + print(pmtf.output) + print('---------------') break index += 1 # if we failed in setup or teardown, - # fill in the remaining tests with not ok + # fill in the remaining tests with ok-skipped count = index tap += 'about to flush the tap output if tests need to be skipped\n' if tcount + 1 != index: for tidx in testlist[index - 1:]: - msg = 'skipped - previous setup or teardown failed' + msg = 'skipped - previous {} failed'.format(stage) tap += 'ok {} - {} # {} {} {}\n'.format( count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) count += 1 -- cgit v1.2.3 From 3adc1c63e288c3f60b1bdee461a0b15447901bcc Mon Sep 17 00:00:00 2001 From: BTaskaya Date: Fri, 23 Feb 2018 22:57:35 +0300 Subject: tc: python3, string formattings This patch converts old type string formattings to new type string formattings for adapting Linux Traffic Control (tc) unit testing suite python3. Linux Traffic Control (tc) unit testing suite's code quality improved is improved with this patch. According to python documentation; "The built-in string class provides the ability to do complex variable substitutions and value formatting via the format() method described in PEP 3101. " but the project was using old type formattings and new type string formattings together, this patch's main purpose is converting all old types to new types. Following files changed: 1. tools/testing/selftests/tc-testing/tdc.py 2. tools/testing/selftests/tc-testing/tdc_batch.py Following PEP rules applied: 1. PEP8 - Code Styling 2. PEP3101 - Advanced Code Formatting Signed-off-by: Batuhan Osman Taskaya Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 2 +- tools/testing/selftests/tc-testing/tdc_batch.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 6c220bc26d9f..7b50775abaf6 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -445,7 +445,7 @@ def generate_case_ids(alltests): for c in alltests: if (c["id"] == ""): while True: - newid = str('%04x' % random.randrange(16**4)) + newid = str('{:04x}'.format(random.randrange(16**4))) if (does_id_exist(alltests, newid)): continue else: diff --git a/tools/testing/selftests/tc-testing/tdc_batch.py b/tools/testing/selftests/tc-testing/tdc_batch.py index 707c6bfef689..52fa539dc662 100755 --- a/tools/testing/selftests/tc-testing/tdc_batch.py +++ b/tools/testing/selftests/tc-testing/tdc_batch.py @@ -49,13 +49,13 @@ index = 0 for i in range(0x100): for j in range(0x100): for k in range(0x100): - mac = ("%02x:%02x:%02x" % (i, j, k)) + mac = ("{:02x}:{:02x}:{:02x}".format(i, j, k)) src_mac = "e4:11:00:" + mac dst_mac = "e4:12:00:" + mac - cmd = ("filter add dev %s %s protocol ip parent ffff: flower %s " - "src_mac %s dst_mac %s action drop %s" % + cmd = ("filter add dev {} {} protocol ip parent ffff: flower {} " + "src_mac {} dst_mac {} action drop {}".format (device, prio, skip, src_mac, dst_mac, share_action)) - file.write("%s\n" % cmd) + file.write("{}\n".format(cmd)) index += 1 if index >= number: file.close() -- cgit v1.2.3 From fe8d662aef26394388bfcd3b96ce123b6d33044b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 26 Feb 2018 22:34:32 +0100 Subject: bpf: unify rlimit handling in selftests Unify memlock handling into bpf_rlimit.h and replace all occurences in BPF kselftests with it. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_rlimit.h | 28 +++++++++++++++++++++++++ tools/testing/selftests/bpf/test_align.c | 6 +----- tools/testing/selftests/bpf/test_dev_cgroup.c | 6 +----- tools/testing/selftests/bpf/test_lpm_map.c | 14 +++---------- tools/testing/selftests/bpf/test_lru_map.c | 6 ++---- tools/testing/selftests/bpf/test_maps.c | 7 ++----- tools/testing/selftests/bpf/test_progs.c | 7 ++----- tools/testing/selftests/bpf/test_tag.c | 4 +--- tools/testing/selftests/bpf/test_tcpbpf_user.c | 6 +----- tools/testing/selftests/bpf/test_verifier.c | 6 +----- tools/testing/selftests/bpf/test_verifier_log.c | 8 ++----- 11 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_rlimit.h (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_rlimit.h b/tools/testing/selftests/bpf/bpf_rlimit.h new file mode 100644 index 000000000000..9dac9b30f8ef --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_rlimit.h @@ -0,0 +1,28 @@ +#include +#include + +static __attribute__((constructor)) void bpf_rlimit_ctor(void) +{ + struct rlimit rlim_old, rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + getrlimit(RLIMIT_MEMLOCK, &rlim_old); + /* For the sake of running the test cases, we temporarily + * set rlimit to infinity in order for kernel to focus on + * errors from actual test cases and not getting noise + * from hitting memlock limits. The limit is on per-process + * basis and not a global one, hence destructor not really + * needed here. + */ + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new) < 0) { + perror("Unable to lift memlock rlimit"); + /* Trying out lower limit, but expect potential test + * case failures from this! + */ + rlim_new.rlim_cur = rlim_old.rlim_cur + (1UL << 20); + rlim_new.rlim_max = rlim_old.rlim_max + (1UL << 20); + setrlimit(RLIMIT_MEMLOCK, &rlim_new); + } +} diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index ff8bd7e3e50c..6b1b302310fe 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c @@ -9,8 +9,6 @@ #include #include -#include - #include #include #include @@ -19,6 +17,7 @@ #include #include "../../../include/linux/filter.h" +#include "bpf_rlimit.h" #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -702,9 +701,6 @@ static int do_test(unsigned int from, unsigned int to) int main(int argc, char **argv) { unsigned int from = 0, to = ARRAY_SIZE(tests); - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); if (argc == 3) { unsigned int l = atoi(argv[argc - 2]); diff --git a/tools/testing/selftests/bpf/test_dev_cgroup.c b/tools/testing/selftests/bpf/test_dev_cgroup.c index 3489cc283433..9c8b50bac7e0 100644 --- a/tools/testing/selftests/bpf/test_dev_cgroup.c +++ b/tools/testing/selftests/bpf/test_dev_cgroup.c @@ -11,13 +11,13 @@ #include #include #include -#include #include #include #include #include "cgroup_helpers.h" +#include "bpf_rlimit.h" #define DEV_CGROUP_PROG "./dev_cgroup.o" @@ -25,15 +25,11 @@ int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; struct bpf_object *obj; int error = EXIT_FAILURE; int prog_fd, cgroup_fd; __u32 prog_cnt; - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - if (bpf_prog_load(DEV_CGROUP_PROG, BPF_PROG_TYPE_CGROUP_DEVICE, &obj, &prog_fd)) { printf("Failed to load DEV_CGROUP program\n"); diff --git a/tools/testing/selftests/bpf/test_lpm_map.c b/tools/testing/selftests/bpf/test_lpm_map.c index 2be87e9ee28d..147e34cfceb7 100644 --- a/tools/testing/selftests/bpf/test_lpm_map.c +++ b/tools/testing/selftests/bpf/test_lpm_map.c @@ -22,10 +22,11 @@ #include #include #include -#include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" struct tlpm_node { struct tlpm_node *next; @@ -736,17 +737,11 @@ static void test_lpm_multi_thread(void) int main(void) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; - int i, ret; + int i; /* we want predictable, pseudo random tests */ srand(0xf00ba1); - /* allow unlimited locked memory */ - ret = setrlimit(RLIMIT_MEMLOCK, &limit); - if (ret < 0) - perror("Unable to lift memlock rlimit"); - test_lpm_basic(); test_lpm_order(); @@ -755,11 +750,8 @@ int main(void) test_lpm_map(i); test_lpm_ipaddr(); - test_lpm_delete(); - test_lpm_get_next_key(); - test_lpm_multi_thread(); printf("test_lpm: OK\n"); diff --git a/tools/testing/selftests/bpf/test_lru_map.c b/tools/testing/selftests/bpf/test_lru_map.c index 8c10c9180c1a..781c7de343be 100644 --- a/tools/testing/selftests/bpf/test_lru_map.c +++ b/tools/testing/selftests/bpf/test_lru_map.c @@ -16,10 +16,11 @@ #include #include -#include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" #define LOCAL_FREE_TARGET (128) #define PERCPU_FREE_TARGET (4) @@ -613,7 +614,6 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free) int main(int argc, char **argv) { - struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; int map_types[] = {BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH}; int map_flags[] = {0, BPF_F_NO_COMMON_LRU}; @@ -621,8 +621,6 @@ int main(int argc, char **argv) setbuf(stdout, NULL); - assert(!setrlimit(RLIMIT_MEMLOCK, &r)); - nr_cpus = bpf_num_possible_cpus(); assert(nr_cpus != -1); printf("nr_cpus:%d\n\n", nr_cpus); diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 9e03a4c356a4..1238733c5b33 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -17,13 +17,14 @@ #include #include -#include #include #include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" static int map_flags; @@ -1126,10 +1127,6 @@ static void run_all_tests(void) int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); - map_flags = 0; run_all_tests(); diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index b549308abd19..27ad5404389e 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -26,7 +26,6 @@ typedef __u16 __sum16; #include #include -#include #include #include @@ -34,9 +33,11 @@ typedef __u16 __sum16; #include #include #include + #include "test_iptunnel_common.h" #include "bpf_util.h" #include "bpf_endian.h" +#include "bpf_rlimit.h" static int error_cnt, pass_cnt; @@ -965,10 +966,6 @@ out: int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); - test_pkt_access(); test_xdp(); test_l4lb_all(); diff --git a/tools/testing/selftests/bpf/test_tag.c b/tools/testing/selftests/bpf/test_tag.c index 8b201895c569..6272c784ca2a 100644 --- a/tools/testing/selftests/bpf/test_tag.c +++ b/tools/testing/selftests/bpf/test_tag.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -21,6 +20,7 @@ #include #include "../../../include/linux/filter.h" +#include "bpf_rlimit.h" static struct bpf_insn prog[BPF_MAXINSNS]; @@ -184,11 +184,9 @@ static void do_test(uint32_t *tests, int start_insns, int fd_map, int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; uint32_t tests = 0; int i, fd_map; - setrlimit(RLIMIT_MEMLOCK, &rinf); fd_map = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(int), 1, BPF_F_NO_PREALLOC); assert(fd_map > 0); diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index 5d73db416460..84ab5163c828 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -12,13 +12,13 @@ #include #include #include -#include #include #include #include #include #include #include "bpf_util.h" +#include "bpf_rlimit.h" #include #include "test_tcpbpf.h" @@ -44,7 +44,6 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; const char *file = "test_tcpbpf_kern.o"; struct tcpbpf_globals g = {0}; int cg_fd, prog_fd, map_fd; @@ -57,9 +56,6 @@ int main(int argc, char **argv) int pid; int rv; - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - if (argc > 1 && strcmp(argv[1], "-d") == 0) debug_flag = true; diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 2164d218322e..bd3a08c7cc15 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -41,7 +40,7 @@ # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 # endif #endif - +#include "bpf_rlimit.h" #include "../../../include/linux/filter.h" #ifndef ARRAY_SIZE @@ -11543,8 +11542,6 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) int main(int argc, char **argv) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - struct rlimit rlim = { 1 << 20, 1 << 20 }; unsigned int from = 0, to = ARRAY_SIZE(tests); bool unpriv = !is_admin(); @@ -11572,6 +11569,5 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - setrlimit(RLIMIT_MEMLOCK, unpriv ? &rlim : &rinf); return do_test(unpriv, from, to); } diff --git a/tools/testing/selftests/bpf/test_verifier_log.c b/tools/testing/selftests/bpf/test_verifier_log.c index e9626cf5607a..8d6918c3b4a2 100644 --- a/tools/testing/selftests/bpf/test_verifier_log.c +++ b/tools/testing/selftests/bpf/test_verifier_log.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -12,6 +11,8 @@ #include +#include "bpf_rlimit.h" + #define LOG_SIZE (1 << 20) #define err(str...) printf("ERROR: " str) @@ -133,16 +134,11 @@ static void test_log_bad(char *log, size_t log_len, int log_level) int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; char full_log[LOG_SIZE]; char log[LOG_SIZE]; size_t want_len; int i; - /* allow unlimited locked memory to have more consistent error code */ - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - memset(log, 1, LOG_SIZE); /* Test incorrect attr */ -- cgit v1.2.3 From b33eb735836224e55cd8182aff9bbb7ddc17f38b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 26 Feb 2018 22:34:33 +0100 Subject: bpf: add tail call tests to test_verifier One of the downsides of the test_bpf module was that since being in kernel space, it couldn't test-run tail calls. Now that the test_verifier has the ability to perform run-time tests, populate the prog array so we actually jump into other BPF programs and can check all corner cases. Most useful in combination with JITs. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 117 ++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index bd3a08c7cc15..9eb05f3135ac 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -2588,6 +2588,62 @@ static struct bpf_test tests[] = { .result_unpriv = REJECT, .result = ACCEPT, }, + { + "runtime/jit: tail_call within bounds, prog once", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 42, + }, + { + "runtime/jit: tail_call within bounds, prog loop", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 1), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 41, + }, + { + "runtime/jit: tail_call within bounds, no prog", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 2), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 1, + }, + { + "runtime/jit: tail_call out of bounds", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 256), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 2, + }, { "runtime/jit: pass negative index to tail_call", .insns = { @@ -2595,11 +2651,12 @@ static struct bpf_test tests[] = { BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), - BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 2), BPF_EXIT_INSN(), }, .fixup_prog = { 1 }, .result = ACCEPT, + .retval = 2, }, { "runtime/jit: pass > 32bit index to tail_call", @@ -2608,11 +2665,12 @@ static struct bpf_test tests[] = { BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), - BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 2), BPF_EXIT_INSN(), }, .fixup_prog = { 2 }, .result = ACCEPT, + .retval = 42, }, { "stack pointer arithmetic", @@ -11278,16 +11336,61 @@ static int create_map(uint32_t size_value, uint32_t max_elem) return fd; } +static int create_prog_dummy1(void) +{ + struct bpf_insn prog[] = { + BPF_MOV64_IMM(BPF_REG_0, 42), + BPF_EXIT_INSN(), + }; + + return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + ARRAY_SIZE(prog), "GPL", 0, NULL, 0); +} + +static int create_prog_dummy2(int mfd, int idx) +{ + struct bpf_insn prog[] = { + BPF_MOV64_IMM(BPF_REG_3, idx), + BPF_LD_MAP_FD(BPF_REG_2, mfd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 41), + BPF_EXIT_INSN(), + }; + + return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + ARRAY_SIZE(prog), "GPL", 0, NULL, 0); +} + static int create_prog_array(void) { - int fd; + int p1key = 0, p2key = 1; + int mfd, p1fd, p2fd; - fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), - sizeof(int), 4, 0); - if (fd < 0) + mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), + sizeof(int), 4, 0); + if (mfd < 0) { printf("Failed to create prog array '%s'!\n", strerror(errno)); + return -1; + } - return fd; + p1fd = create_prog_dummy1(); + p2fd = create_prog_dummy2(mfd, p2key); + if (p1fd < 0 || p2fd < 0) + goto out; + if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) + goto out; + if (bpf_map_update_elem(mfd, &p2key, &p2fd, BPF_ANY) < 0) + goto out; + close(p2fd); + close(p1fd); + + return mfd; +out: + close(p2fd); + close(p1fd); + close(mfd); + return -1; } static int create_map_in_map(void) -- cgit v1.2.3 From a52b839752aab7063c38c1cb7b8e63efc54e3c30 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 26 Feb 2018 09:53:15 -0800 Subject: selftests: Add fib-onlink-tests.sh to TEST_PROGS Fixes: 153e1b84f477 ("selftests: Add FIB onlink tests") Reported-by: Ido Schimmel Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index d7c30d366935..229a038966e3 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa -- cgit v1.2.3 From 67490e34ba2b1c02fb554a8059cd6ce12b47ccfb Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Tue, 27 Feb 2018 09:52:42 -0800 Subject: selftests/net: revert the zerocopy Rx path for PF_RDS In preparation for optimized reception of zerocopy completion, revert the Rx side changes introduced by Commit dfb8434b0a94 ("selftests/net: add zerocopy support for PF_RDS test case") Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 67 ------------------------------ 1 file changed, 67 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 5cc2a53bb71c..eff9cf2ff04d 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -344,26 +344,6 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } -static int do_process_zerocopy_cookies(struct sock_extended_err *serr, - uint32_t *ckbuf, size_t nbytes) -{ - int ncookies, i; - - if (serr->ee_errno != 0) - error(1, 0, "serr: wrong error code: %u", serr->ee_errno); - ncookies = serr->ee_data; - if (ncookies > SO_EE_ORIGIN_MAX_ZCOOKIES) - error(1, 0, "Returned %d cookies, max expected %d\n", - ncookies, SO_EE_ORIGIN_MAX_ZCOOKIES); - if (nbytes != ncookies * sizeof(uint32_t)) - error(1, 0, "Expected %d cookies, got %ld\n", - ncookies, nbytes/sizeof(uint32_t)); - for (i = 0; i < ncookies; i++) - if (cfg_verbose >= 2) - fprintf(stderr, "%d\n", ckbuf[i]); - return ncookies; -} - static bool do_recv_completion(int fd) { struct sock_extended_err *serr; @@ -372,17 +352,10 @@ static bool do_recv_completion(int fd) uint32_t hi, lo, range; int ret, zerocopy; char control[100]; - uint32_t ckbuf[SO_EE_ORIGIN_MAX_ZCOOKIES]; - struct iovec iov; msg.msg_control = control; msg.msg_controllen = sizeof(control); - iov.iov_base = ckbuf; - iov.iov_len = (SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(ckbuf[0])); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - ret = recvmsg(fd, &msg, MSG_ERRQUEUE); if (ret == -1 && errno == EAGAIN) return false; @@ -402,10 +375,6 @@ static bool do_recv_completion(int fd) serr = (void *) CMSG_DATA(cm); - if (serr->ee_origin == SO_EE_ORIGIN_ZCOOKIE) { - completions += do_process_zerocopy_cookies(serr, ckbuf, ret); - return true; - } if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) error(1, 0, "serr: wrong origin: %u", serr->ee_origin); if (serr->ee_errno != 0) @@ -631,40 +600,6 @@ static void do_flush_datagram(int fd, int type) bytes += cfg_payload_len; } - -static void do_recvmsg(int fd) -{ - int ret, off = 0; - char *buf; - struct iovec iov; - struct msghdr msg; - struct sockaddr_storage din; - - buf = calloc(cfg_payload_len, sizeof(char)); - iov.iov_base = buf; - iov.iov_len = cfg_payload_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &din; - msg.msg_namelen = sizeof(din); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ret = recvmsg(fd, &msg, MSG_TRUNC); - - if (ret == -1) - error(1, errno, "recv"); - if (ret != cfg_payload_len) - error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); - - if (memcmp(buf + off, payload, ret)) - error(1, 0, "recv: data mismatch"); - - free(buf); - packets++; - bytes += cfg_payload_len; -} - static void do_rx(int domain, int type, int protocol) { uint64_t tstop; @@ -676,8 +611,6 @@ static void do_rx(int domain, int type, int protocol) do { if (type == SOCK_STREAM) do_flush_tcp(fd); - else if (domain == PF_RDS) - do_recvmsg(fd); else do_flush_datagram(fd, type); -- cgit v1.2.3 From 6f3899e602b0f4ec3d62ff385bb805e7109defa4 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Tue, 27 Feb 2018 09:52:44 -0800 Subject: selftests/net: reap zerocopy completions passed up as ancillary data. PF_RDS sockets pass up cookies for zerocopy completion as ancillary data. Update msg_zerocopy to reap this information. Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 65 ++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index eff9cf2ff04d..406cc70c571d 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -344,7 +344,53 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } -static bool do_recv_completion(int fd) +static uint32_t do_process_zerocopy_cookies(struct rds_zcopy_cookies *ck) +{ + int i; + + if (ck->num > RDS_MAX_ZCOOKIES) + error(1, 0, "Returned %d cookies, max expected %d\n", + ck->num, RDS_MAX_ZCOOKIES); + for (i = 0; i < ck->num; i++) + if (cfg_verbose >= 2) + fprintf(stderr, "%d\n", ck->cookies[i]); + return ck->num; +} + +static bool do_recvmsg_completion(int fd) +{ + char cmsgbuf[CMSG_SPACE(sizeof(struct rds_zcopy_cookies))]; + struct rds_zcopy_cookies *ck; + struct cmsghdr *cmsg; + struct msghdr msg; + bool ret = false; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + if (recvmsg(fd, &msg, MSG_DONTWAIT)) + return ret; + + if (msg.msg_flags & MSG_CTRUNC) + error(1, errno, "recvmsg notification: truncated"); + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_RDS && + cmsg->cmsg_type == RDS_CMSG_ZCOPY_COMPLETION) { + + ck = (struct rds_zcopy_cookies *)CMSG_DATA(cmsg); + completions += do_process_zerocopy_cookies(ck); + ret = true; + break; + } + error(0, 0, "ignoring cmsg at level %d type %d\n", + cmsg->cmsg_level, cmsg->cmsg_type); + } + return ret; +} + +static bool do_recv_completion(int fd, int domain) { struct sock_extended_err *serr; struct msghdr msg = {}; @@ -353,6 +399,9 @@ static bool do_recv_completion(int fd) int ret, zerocopy; char control[100]; + if (domain == PF_RDS) + return do_recvmsg_completion(fd); + msg.msg_control = control; msg.msg_controllen = sizeof(control); @@ -409,20 +458,20 @@ static bool do_recv_completion(int fd) } /* Read all outstanding messages on the errqueue */ -static void do_recv_completions(int fd) +static void do_recv_completions(int fd, int domain) { - while (do_recv_completion(fd)) {} + while (do_recv_completion(fd, domain)) {} } /* Wait for all remaining completions on the errqueue */ -static void do_recv_remaining_completions(int fd) +static void do_recv_remaining_completions(int fd, int domain) { int64_t tstop = gettimeofday_ms() + cfg_waittime_ms; while (completions < expected_completions && gettimeofday_ms() < tstop) { - if (do_poll(fd, POLLERR)) - do_recv_completions(fd); + if (do_poll(fd, domain == PF_RDS ? POLLIN : POLLERR)) + do_recv_completions(fd, domain); } if (completions < expected_completions) @@ -503,13 +552,13 @@ static void do_tx(int domain, int type, int protocol) while (!do_poll(fd, POLLOUT)) { if (cfg_zerocopy) - do_recv_completions(fd); + do_recv_completions(fd, domain); } } while (gettimeofday_ms() < tstop); if (cfg_zerocopy) - do_recv_remaining_completions(fd); + do_recv_remaining_completions(fd, domain); if (close(fd)) error(1, errno, "close"); -- cgit v1.2.3 From 73bae6736b6b577b52fbba2d4b71a5a3e9920fb5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:06 +0200 Subject: selftests: forwarding: Add initial testing framework Add initial framework to test packet forwarding functionality. The tests can run on actual devices using loop-backed cables or using veth pairs. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/.gitignore | 1 + tools/testing/selftests/net/forwarding/README | 56 ++++ .../selftests/net/forwarding/bridge_vlan_aware.sh | 83 ++++++ tools/testing/selftests/net/forwarding/config | 12 + .../net/forwarding/forwarding.config.sample | 31 +++ tools/testing/selftests/net/forwarding/lib.sh | 282 +++++++++++++++++++++ 6 files changed, 465 insertions(+) create mode 100644 tools/testing/selftests/net/forwarding/.gitignore create mode 100644 tools/testing/selftests/net/forwarding/README create mode 100755 tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh create mode 100644 tools/testing/selftests/net/forwarding/config create mode 100644 tools/testing/selftests/net/forwarding/forwarding.config.sample create mode 100644 tools/testing/selftests/net/forwarding/lib.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/.gitignore b/tools/testing/selftests/net/forwarding/.gitignore new file mode 100644 index 000000000000..a793eef5b876 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/.gitignore @@ -0,0 +1 @@ +forwarding.config diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README new file mode 100644 index 000000000000..4a0964c42860 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/README @@ -0,0 +1,56 @@ +Motivation +========== + +One of the nice things about network namespaces is that they allow one +to easily create and test complex environments. + +Unfortunately, these namespaces can not be used with actual switching +ASICs, as their ports can not be migrated to other network namespaces +(NETIF_F_NETNS_LOCAL) and most of them probably do not support the +L1-separation provided by namespaces. + +However, a similar kind of flexibility can be achieved by using VRFs and +by looping the switch ports together. For example: + + br0 + + + vrf-h1 | vrf-h2 + + +---+----+ + + | | | | + 192.0.2.1/24 + + + + 192.0.2.2/24 + swp1 swp2 swp3 swp4 + + + + + + | | | | + +--------+ +--------+ + +The VRFs act as lightweight namespaces representing hosts connected to +the switch. + +This approach for testing switch ASICs has several advantages over the +traditional method that requires multiple physical machines, to name a +few: + +1. Only the device under test (DUT) is being tested without noise from +other system. + +2. Ability to easily provision complex topologies. Testing bridging +between 4-ports LAGs or 8-way ECMP requires many physical links that are +not always available. With the VRF-based approach one merely needs to +loopback more ports. + +These tests are written with switch ASICs in mind, but they can be run +on any Linux box using veth pairs to emulate physical loopbacks. + +Guidelines for Writing Tests +============================ + +o Where possible, reuse an existing topology for different tests instead + of recreating the same topology. +o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and + RFC 5737, respectively. +o Where possible, tests shall be written so that they can be reused by + multiple topologies and added to lib.sh. +o Checks shall be added to lib.sh for any external dependencies. +o Code shall be checked using ShellCheck [1] prior to submission. + +1. https://www.shellcheck.net/ diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh new file mode 100755 index 000000000000..e6faa9548460 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +switch_create() +{ + ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0 + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + + ip link set dev br0 up + ip link set dev $swp1 up + ip link set dev $swp2 up +} + +switch_destroy() +{ + ip link set dev $swp2 down + ip link set dev $swp1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 192.0.2.2 +ping6_test $h1 2001:db8:1::2 + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config new file mode 100644 index 000000000000..5cd2aed97958 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/config @@ -0,0 +1,12 @@ +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NET_VRF=m +CONFIG_BPF_SYSCALL=y +CONFIG_CGROUP_BPF=y +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_ACT_GACT=m +CONFIG_VETH=m diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample new file mode 100644 index 000000000000..ab235c124f20 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Topology description. p1 looped back to p2, p3 to p4 and so on. +declare -A NETIFS + +NETIFS[p1]=veth0 +NETIFS[p2]=veth1 +NETIFS[p3]=veth2 +NETIFS[p4]=veth3 +NETIFS[p5]=veth4 +NETIFS[p6]=veth5 +NETIFS[p7]=veth6 +NETIFS[p8]=veth7 + +############################################################################## +# Defines + +# IPv4 ping utility name +PING=ping +# IPv6 ping utility name. Some distributions use 'ping' for IPv6. +PING6=ping6 +# Packet generator. Some distributions use 'mz'. +MZ=mausezahn +# Time to wait after interfaces participating in the test are all UP +WAIT_TIME=5 +# Whether to pause on failure or not. +PAUSE_ON_FAIL=no +# Whether to pause on cleanup or not. +PAUSE_ON_CLEANUP=no diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh new file mode 100644 index 000000000000..ff6550e9ddaf --- /dev/null +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -0,0 +1,282 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Defines + +# Can be overridden by the configuration file. +PING=${PING:=ping} +PING6=${PING6:=ping6} +WAIT_TIME=${WAIT_TIME:=5} +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} +PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} + +if [[ -f forwarding.config ]]; then + source forwarding.config +fi + +############################################################################## +# Sanity checks + +if [[ "$(id -u)" -ne 0 ]]; then + echo "SKIP: need root privileges" + exit 0 +fi + +tc -j &> /dev/null +if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old, missing JSON support" + exit 0 +fi + +if [[ ! -x "$(command -v jq)" ]]; then + echo "SKIP: jq not installed" + exit 0 +fi + +if [[ ! -v NUM_NETIFS ]]; then + echo "SKIP: importer does not define \"NUM_NETIFS\"" + exit 0 +fi + +############################################################################## +# Network interfaces configuration + +for i in $(eval echo {1..$NUM_NETIFS}); do + ip link show dev ${NETIFS[p$i]} &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: could not find all required interfaces" + exit 0 + fi +done + +############################################################################## +# Helpers + +# Exit status to return at the end. Set in case one of the tests fails. +EXIT_STATUS=0 +# Per-test return value. Clear at the beginning of each test. +RET=0 + +check_err() +{ + local err=$1 + local msg=$2 + + if [[ $RET -eq 0 && $err -ne 0 ]]; then + RET=$err + retmsg=$msg + fi +} + +check_fail() +{ + local err=$1 + local msg=$2 + + if [[ $RET -eq 0 && $err -eq 0 ]]; then + RET=1 + retmsg=$msg + fi +} + +log_test() +{ + local test_name=$1 + local opt_str=$2 + + if [[ $# -eq 2 ]]; then + opt_str="($opt_str)" + fi + + if [[ $RET -ne 0 ]]; then + EXIT_STATUS=1 + printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str" + if [[ ! -z "$retmsg" ]]; then + printf "\t%s\n" "$retmsg" + fi + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo "Hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + return 1 + fi + + printf "TEST: %-60s [PASS]\n" "$test_name $opt_str" + return 0 +} + +setup_wait() +{ + for i in $(eval echo {1..$NUM_NETIFS}); do + while true; do + ip link show dev ${NETIFS[p$i]} up \ + | grep 'state UP' &> /dev/null + if [[ $? -ne 0 ]]; then + sleep 1 + else + break + fi + done + done + + # Make sure links are ready. + sleep $WAIT_TIME +} + +pre_cleanup() +{ + if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then + echo "Pausing before cleanup, hit any key to continue" + read + fi +} + +vrf_prepare() +{ + ip -4 rule add pref 32765 table local + ip -4 rule del pref 0 + ip -6 rule add pref 32765 table local + ip -6 rule del pref 0 +} + +vrf_cleanup() +{ + ip -6 rule add pref 0 table local + ip -6 rule del pref 32765 + ip -4 rule add pref 0 table local + ip -4 rule del pref 32765 +} + +__last_tb_id=0 +declare -A __TB_IDS + +__vrf_td_id_assign() +{ + local vrf_name=$1 + + __last_tb_id=$((__last_tb_id + 1)) + __TB_IDS[$vrf_name]=$__last_tb_id + return $__last_tb_id +} + +__vrf_td_id_lookup() +{ + local vrf_name=$1 + + return ${__TB_IDS[$vrf_name]} +} + +vrf_create() +{ + local vrf_name=$1 + local tb_id + + __vrf_td_id_assign $vrf_name + tb_id=$? + + ip link add dev $vrf_name type vrf table $tb_id + ip -4 route add table $tb_id unreachable default metric 4278198272 + ip -6 route add table $tb_id unreachable default metric 4278198272 +} + +vrf_destroy() +{ + local vrf_name=$1 + local tb_id + + __vrf_td_id_lookup $vrf_name + tb_id=$? + + ip -6 route del table $tb_id unreachable default metric 4278198272 + ip -4 route del table $tb_id unreachable default metric 4278198272 + ip link del dev $vrf_name +} + +__addr_add_del() +{ + local if_name=$1 + local add_del=$2 + local array + + shift + shift + array=("${@}") + + for addrstr in "${array[@]}"; do + ip address $add_del $addrstr dev $if_name + done +} + +simple_if_init() +{ + local if_name=$1 + local vrf_name + local array + + shift + vrf_name=v$if_name + array=("${@}") + + vrf_create $vrf_name + ip link set dev $if_name master $vrf_name + ip link set dev $vrf_name up + ip link set dev $if_name up + + __addr_add_del $if_name add "${array[@]}" +} + +simple_if_fini() +{ + local if_name=$1 + local vrf_name + local array + + shift + vrf_name=v$if_name + array=("${@}") + + __addr_add_del $if_name del "${array[@]}" + + ip link set dev $if_name down + vrf_destroy $vrf_name +} + +master_name_get() +{ + local if_name=$1 + + ip -j link show dev $if_name | jq -r '.[]["master"]' +} + +############################################################################## +# Tests + +ping_test() +{ + local if_name=$1 + local dip=$2 + local vrf_name + + RET=0 + + vrf_name=$(master_name_get $if_name) + ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null + check_err $? + log_test "ping" +} + +ping6_test() +{ + local if_name=$1 + local dip=$2 + local vrf_name + + RET=0 + + vrf_name=$(master_name_get $if_name) + ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null + check_err $? + log_test "ping6" +} -- cgit v1.2.3 From d4deb01467ec9ed33fe0f4b4fa4632c94f2dd8c9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:07 +0200 Subject: selftests: forwarding: Add a test for FDB learning Send a packet with a specific destination MAC, make sure it was learned on the ingress port and then aged-out. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 5 +- tools/testing/selftests/net/forwarding/lib.sh | 92 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index e6faa9548460..1ba119f28963 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -26,7 +26,9 @@ h2_destroy() switch_create() { - ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0 + # 10 Seconds ageing time. + ip link add dev br0 type bridge vlan_filtering 1 ageing_time 1000 \ + mcast_snooping 0 ip link set dev $swp1 master br0 ip link set dev $swp2 master br0 @@ -79,5 +81,6 @@ setup_wait ping_test $h1 192.0.2.2 ping6_test $h1 2001:db8:1::2 +learning_test "br0" $swp1 $h1 $h2 exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index ff6550e9ddaf..21af63e860dc 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -7,6 +7,7 @@ # Can be overridden by the configuration file. PING=${PING:=ping} PING6=${PING6:=ping6} +MZ=${MZ:=mausezahn} WAIT_TIME=${WAIT_TIME:=5} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} @@ -34,6 +35,11 @@ if [[ ! -x "$(command -v jq)" ]]; then exit 0 fi +if [[ ! -x "$(command -v $MZ)" ]]; then + echo "SKIP: $MZ not installed" + exit 0 +fi + if [[ ! -v NUM_NETIFS ]]; then echo "SKIP: importer does not define \"NUM_NETIFS\"" exit 0 @@ -250,6 +256,17 @@ master_name_get() ip -j link show dev $if_name | jq -r '.[]["master"]' } +bridge_ageing_time_get() +{ + local bridge=$1 + local ageing_time + + # Need to divide by 100 to convert to seconds. + ageing_time=$(ip -j -d link show dev $bridge \ + | jq '.[]["linkinfo"]["info_data"]["ageing_time"]') + echo $((ageing_time / 100)) +} + ############################################################################## # Tests @@ -280,3 +297,78 @@ ping6_test() check_err $? log_test "ping6" } + +learning_test() +{ + local bridge=$1 + local br_port1=$2 # Connected to `host1_if`. + local host1_if=$3 + local host2_if=$4 + local mac=de:ad:be:ef:13:37 + local ageing_time + + RET=0 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + # Disable unknown unicast flooding on `br_port1` to make sure + # packets are only forwarded through the port after a matching + # FDB entry was installed. + bridge link set dev $br_port1 flood off + + tc qdisc add dev $host1_if ingress + tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \ + flower dst_mac $mac action drop + + $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q + sleep 1 + + tc -j -s filter show dev $host1_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + check_fail $? "Packet reached second host when should not" + + $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q + sleep 1 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_err $? "Did not find FDB record when should" + + $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q + sleep 1 + + tc -j -s filter show dev $host1_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + check_err $? "Packet did not reach second host when should" + + # Wait for 10 seconds after the ageing time to make sure FDB + # record was aged-out. + ageing_time=$(bridge_ageing_time_get $bridge) + sleep $((ageing_time + 10)) + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + bridge link set dev $br_port1 learning off + + $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q + sleep 1 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + bridge link set dev $br_port1 learning on + + tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower + tc qdisc del dev $host1_if ingress + + bridge link set dev $br_port1 flood on + + log_test "FDB learning" +} -- cgit v1.2.3 From 236dd50bf67a2ab5fd39d82e712d1fafdd4c602d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:08 +0200 Subject: selftests: forwarding: Add a test for flooded traffic Add test cases for unknown unicast and unregistered multicast flooding. For each traffic type, turn off flooding on one bridged port and inject a packet of the specified type through the second bridged port. Make sure the packet was not received by checking the ACL counters on the other end. Later, turn on flooding and make sure the packet was received. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 1 + tools/testing/selftests/net/forwarding/lib.sh | 89 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index 1ba119f28963..651998e70557 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -82,5 +82,6 @@ setup_wait ping_test $h1 192.0.2.2 ping6_test $h1 2001:db8:1::2 learning_test "br0" $swp1 $h1 $h2 +flood_test $swp2 $h1 $h2 exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 21af63e860dc..e2a4ee8946ef 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -372,3 +372,92 @@ learning_test() log_test "FDB learning" } + +flood_test_do() +{ + local should_flood=$1 + local mac=$2 + local ip=$3 + local host1_if=$4 + local host2_if=$5 + local err=0 + + # Add an ACL on `host2_if` which will tell us whether the packet + # was flooded to it or not. + tc qdisc add dev $host2_if ingress + tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \ + flower dst_mac $mac action drop + + $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q + sleep 1 + + tc -j -s filter show dev $host2_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + if [[ $? -ne 0 && $should_flood == "true" || \ + $? -eq 0 && $should_flood == "false" ]]; then + err=1 + fi + + tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower + tc qdisc del dev $host2_if ingress + + return $err +} + +flood_unicast_test() +{ + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + local mac=de:ad:be:ef:13:37 + local ip=192.0.2.100 + + RET=0 + + bridge link set dev $br_port flood off + + flood_test_do false $mac $ip $host1_if $host2_if + check_err $? "Packet flooded when should not" + + bridge link set dev $br_port flood on + + flood_test_do true $mac $ip $host1_if $host2_if + check_err $? "Packet was not flooded when should" + + log_test "Unknown unicast flood" +} + +flood_multicast_test() +{ + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + local mac=01:00:5e:00:00:01 + local ip=239.0.0.1 + + RET=0 + + bridge link set dev $br_port mcast_flood off + + flood_test_do false $mac $ip $host1_if $host2_if + check_err $? "Packet flooded when should not" + + bridge link set dev $br_port mcast_flood on + + flood_test_do true $mac $ip $host1_if $host2_if + check_err $? "Packet was not flooded when should" + + log_test "Unregistered multicast flood" +} + +flood_test() +{ + # `br_port` is connected to `host2_if` + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + + flood_unicast_test $br_port $host1_if $host2_if + flood_multicast_test $br_port $host1_if $host2_if +} -- cgit v1.2.3 From 7b7bc875559c0c06406d77a7f71e3c0e289a60be Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:09 +0200 Subject: selftests: forwarding: Add a test for basic IPv4 and IPv6 routing Configure two hosts which are directly connected to the same router and test IPv4 and IPv6 ping. Use a large MTU and check that ping is unaffected. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 15 +++ tools/testing/selftests/net/forwarding/router.sh | 125 +++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index e2a4ee8946ef..962153b7181b 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -267,6 +267,21 @@ bridge_ageing_time_get() echo $((ageing_time / 100)) } +forwarding_enable() +{ + ipv4_fwd=$(sysctl -n net.ipv4.conf.all.forwarding) + ipv6_fwd=$(sysctl -n net.ipv6.conf.all.forwarding) + + sysctl -q -w net.ipv4.conf.all.forwarding=1 + sysctl -q -w net.ipv6.conf.all.forwarding=1 +} + +forwarding_restore() +{ + sysctl -q -w net.ipv6.conf.all.forwarding=$ipv6_fwd + sysctl -q -w net.ipv4.conf.all.forwarding=$ipv4_fwd +} + ############################################################################## # Tests diff --git a/tools/testing/selftests/net/forwarding/router.sh b/tools/testing/selftests/net/forwarding/router.sh new file mode 100755 index 000000000000..cc6a14abfa87 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + vrf_create "vrf-h1" + ip link set dev $h1 master vrf-h1 + + ip link set dev vrf-h1 up + ip link set dev $h1 up + + ip address add 192.0.2.2/24 dev $h1 + ip address add 2001:db8:1::2/64 dev $h1 + + ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1 + ip route add 2001:db8:2::/64 vrf vrf-h1 nexthop via 2001:db8:1::1 +} + +h1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-h1 + ip route del 198.51.100.0/24 vrf vrf-h1 + + ip address del 2001:db8:1::2/64 dev $h1 + ip address del 192.0.2.2/24 dev $h1 + + ip link set dev $h1 down + vrf_destroy "vrf-h1" +} + +h2_create() +{ + vrf_create "vrf-h2" + ip link set dev $h2 master vrf-h2 + + ip link set dev vrf-h2 up + ip link set dev $h2 up + + ip address add 198.51.100.2/24 dev $h2 + ip address add 2001:db8:2::2/64 dev $h2 + + ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1 + ip route add 2001:db8:1::/64 vrf vrf-h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-h2 + ip route del 192.0.2.0/24 vrf vrf-h2 + + ip address del 2001:db8:2::2/64 dev $h2 + ip address del 198.51.100.2/24 dev $h2 + + ip link set dev $h2 down + vrf_destroy "vrf-h2" +} + +router_create() +{ + ip link set dev $rp1 up + ip link set dev $rp2 up + + ip address add 192.0.2.1/24 dev $rp1 + ip address add 2001:db8:1::1/64 dev $rp1 + + ip address add 198.51.100.1/24 dev $rp2 + ip address add 2001:db8:2::1/64 dev $rp2 +} + +router_destroy() +{ + ip address del 2001:db8:2::1/64 dev $rp2 + ip address del 198.51.100.1/24 dev $rp2 + + ip address del 2001:db8:1::1/64 dev $rp1 + ip address del 192.0.2.1/24 dev $rp1 + + ip link set dev $rp2 down + ip link set dev $rp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + rp1=${NETIFS[p2]} + + rp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + router_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 198.51.100.2 +ping6_test $h1 2001:db8:2::2 + +exit $EXIT_STATUS -- cgit v1.2.3 From 937eeb3482748bb85486070e10b5fbeb6b973f63 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:10 +0200 Subject: selftests: forwarding: Create test topology for multipath routing Create a topology with two hosts, each directly connected to a different router. Both routers are connected using two links, enabling multipath routing. Test IPv4 and IPv6 ping using default MTU and large MTU. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router_multipath.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh new file mode 100755 index 000000000000..86d189b42e9b --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -0,0 +1,209 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=8 +source lib.sh + +h1_create() +{ + vrf_create "vrf-h1" + ip link set dev $h1 master vrf-h1 + + ip link set dev vrf-h1 up + ip link set dev $h1 up + + ip address add 192.0.2.2/24 dev $h1 + ip address add 2001:db8:1::2/64 dev $h1 + + ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1 + ip route add 2001:db8:2::/64 vrf vrf-h1 nexthop via 2001:db8:1::1 +} + +h1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-h1 + ip route del 198.51.100.0/24 vrf vrf-h1 + + ip address del 2001:db8:1::2/64 dev $h1 + ip address del 192.0.2.2/24 dev $h1 + + ip link set dev $h1 down + vrf_destroy "vrf-h1" +} + +h2_create() +{ + vrf_create "vrf-h2" + ip link set dev $h2 master vrf-h2 + + ip link set dev vrf-h2 up + ip link set dev $h2 up + + ip address add 198.51.100.2/24 dev $h2 + ip address add 2001:db8:2::2/64 dev $h2 + + ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1 + ip route add 2001:db8:1::/64 vrf vrf-h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-h2 + ip route del 192.0.2.0/24 vrf vrf-h2 + + ip address del 2001:db8:2::2/64 dev $h2 + ip address del 198.51.100.2/24 dev $h2 + + ip link set dev $h2 down + vrf_destroy "vrf-h2" +} + +router1_create() +{ + vrf_create "vrf-r1" + ip link set dev $rp11 master vrf-r1 + ip link set dev $rp12 master vrf-r1 + ip link set dev $rp13 master vrf-r1 + + ip link set dev vrf-r1 up + ip link set dev $rp11 up + ip link set dev $rp12 up + ip link set dev $rp13 up + + ip address add 192.0.2.1/24 dev $rp11 + ip address add 2001:db8:1::1/64 dev $rp11 + + ip address add 169.254.2.12/24 dev $rp12 + ip address add fe80:2::12/64 dev $rp12 + + ip address add 169.254.3.13/24 dev $rp13 + ip address add fe80:3::13/64 dev $rp13 + + ip route add 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 \ + nexthop via 169.254.3.23 dev $rp13 + ip route add 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 +} + +router1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-r1 + ip route del 198.51.100.0/24 vrf vrf-r1 + + ip address del fe80:3::13/64 dev $rp13 + ip address del 169.254.3.13/24 dev $rp13 + + ip address del fe80:2::12/64 dev $rp12 + ip address del 169.254.2.12/24 dev $rp12 + + ip address del 2001:db8:1::1/64 dev $rp11 + ip address del 192.0.2.1/24 dev $rp11 + + ip link set dev $rp13 down + ip link set dev $rp12 down + ip link set dev $rp11 down + + vrf_destroy "vrf-r1" +} + +router2_create() +{ + vrf_create "vrf-r2" + ip link set dev $rp21 master vrf-r2 + ip link set dev $rp22 master vrf-r2 + ip link set dev $rp23 master vrf-r2 + + ip link set dev vrf-r2 up + ip link set dev $rp21 up + ip link set dev $rp22 up + ip link set dev $rp23 up + + ip address add 198.51.100.1/24 dev $rp21 + ip address add 2001:db8:2::1/64 dev $rp21 + + ip address add 169.254.2.22/24 dev $rp22 + ip address add fe80:2::22/64 dev $rp22 + + ip address add 169.254.3.23/24 dev $rp23 + ip address add fe80:3::23/64 dev $rp23 + + ip route add 192.0.2.0/24 vrf vrf-r2 \ + nexthop via 169.254.2.12 dev $rp22 \ + nexthop via 169.254.3.13 dev $rp23 + ip route add 2001:db8:1::/64 vrf vrf-r2 \ + nexthop via fe80:2::12 dev $rp22 \ + nexthop via fe80:3::13 dev $rp23 +} + +router2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-r2 + ip route del 192.0.2.0/24 vrf vrf-r2 + + ip address del fe80:3::23/64 dev $rp23 + ip address del 169.254.3.23/24 dev $rp23 + + ip address del fe80:2::22/64 dev $rp22 + ip address del 169.254.2.22/24 dev $rp22 + + ip address del 2001:db8:2::1/64 dev $rp21 + ip address del 198.51.100.1/24 dev $rp21 + + ip link set dev $rp23 down + ip link set dev $rp22 down + ip link set dev $rp21 down + + vrf_destroy "vrf-r2" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + rp11=${NETIFS[p2]} + + rp12=${NETIFS[p3]} + rp22=${NETIFS[p4]} + + rp13=${NETIFS[p5]} + rp23=${NETIFS[p6]} + + rp21=${NETIFS[p7]} + h2=${NETIFS[p8]} + + vrf_prepare + + h1_create + h2_create + + router1_create + router2_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router2_destroy + router1_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 198.51.100.2 +ping6_test $h1 2001:db8:2::2 + +exit $EXIT_STATUS -- cgit v1.2.3 From 3d578d879517a97f4af867e6a8a021baf15e5101 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:11 +0200 Subject: selftests: forwarding: Test IPv4 weighted nexthops Use different weights for the multipath route configured on the first router and check that the different flows generated by the first host are distributed according to the provided weights. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 14 ++++ .../selftests/net/forwarding/router_multipath.sh | 77 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 962153b7181b..6866f4a4bc4e 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -113,6 +113,13 @@ log_test() return 0 } +log_info() +{ + local msg=$1 + + echo "INFO: $msg" +} + setup_wait() { for i in $(eval echo {1..$NUM_NETIFS}); do @@ -256,6 +263,13 @@ master_name_get() ip -j link show dev $if_name | jq -r '.[]["master"]' } +link_stats_tx_packets_get() +{ + local if_name=$1 + + ip -j -s link show dev $if_name | jq '.[]["stats64"]["tx"]["packets"]' +} + bridge_ageing_time_get() { local bridge=$1 diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 86d189b42e9b..5b425dffb5d0 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -158,6 +158,82 @@ router2_destroy() vrf_destroy "vrf-r2" } +multipath_eval() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local packets_rp12=$3 + local packets_rp13=$4 + local weights_ratio packets_ratio diff + + RET=0 + + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then + weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ + | bc -l) + packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \ + | bc -l) + else + weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" | \ + bc -l) + packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" | \ + bc -l) + fi + + diff=$(echo $weights_ratio - $packets_ratio | bc -l) + diff=${diff#-} + + test "$(echo "$diff / $weights_ratio > 0.1" | bc -l)" -eq 0 + check_err $? "Too large discrepancy between expected and measured ratios" + log_test "Multipath" + log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" +} + +multipath4_test() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + local hash_policy + + # Transmit multiple flows from h1 to h2 and make sure they are + # distributed between both multipath links (rp12 and rp13) + # according to the configured weights. + hash_policy=$(sysctl -n net.ipv4.fib_multipath_hash_policy) + sysctl -q -w net.ipv4.fib_multipath_hash_policy=1 + ip route replace 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 weight $weight_rp12 \ + nexthop via 169.254.3.23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + ip vrf exec vrf-h1 $MZ -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \ + -d 1msec -t udp "sp=1024,dp=0-32768" + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + # Restore settings. + ip route replace 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 \ + nexthop via 169.254.3.23 dev $rp13 + sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy +} + +multipath_test() +{ + log_info "Running IPv4 multipath tests" + multipath4_test 1 1 + multipath4_test 2 1 + multipath4_test 11 45 +} + setup_prepare() { h1=${NETIFS[p1]} @@ -205,5 +281,6 @@ setup_wait ping_test $h1 198.51.100.2 ping6_test $h1 2001:db8:2::2 +multipath_test exit $EXIT_STATUS -- cgit v1.2.3 From 4fb20ae13711ee05fba6e5dd2b81a83d9e5b5249 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:12 +0200 Subject: selftests: forwarding: Test IPv6 weighted nexthops Have one host generate 16K IPv6 echo requests with a random flow label and check that they are distributed between both multipath links according to the provided weights. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 5b425dffb5d0..d31888e3133e 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -226,12 +226,48 @@ multipath4_test() sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy } +multipath6_test() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 weight $weight_rp12 \ + nexthop via fe80:3::23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + # Generate 16384 echo requests, each with a random flow label. + for _ in $(seq 1 16384); do + ip vrf exec vrf-h1 ping 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null + done + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 +} + multipath_test() { log_info "Running IPv4 multipath tests" multipath4_test 1 1 multipath4_test 2 1 multipath4_test 11 45 + + log_info "Running IPv6 multipath tests" + multipath6_test 1 1 + multipath6_test 2 1 + multipath6_test 11 45 } setup_prepare() -- cgit v1.2.3 From 2f19f2125d824fc607359f6d9248bd765edf7183 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:13 +0200 Subject: selftests: forwarding: Add tc offload check helper Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 6866f4a4bc4e..92e46426bd1d 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -296,6 +296,19 @@ forwarding_restore() sysctl -q -w net.ipv4.conf.all.forwarding=$ipv4_fwd } +tc_offload_check() +{ + for i in $(eval echo {1..$NUM_NETIFS}); do + ethtool -k ${NETIFS[p$i]} \ + | grep "hw-tc-offload: on" &> /dev/null + if [[ $? -ne 0 ]]; then + return 1 + fi + done + + return 0 +} + ############################################################################## # Tests -- cgit v1.2.3 From 4e4272d2a68dcdd2555774dba9d8b237fe0eb63d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:14 +0200 Subject: selftests: forwarding: Add MAC get helper Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 92e46426bd1d..083a16eb7803 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -270,6 +270,13 @@ link_stats_tx_packets_get() ip -j -s link show dev $if_name | jq '.[]["stats64"]["tx"]["packets"]' } +mac_get() +{ + local if_name=$1 + + ip -j link show dev $if_name | jq -r '.[]["address"]' +} + bridge_ageing_time_get() { local bridge=$1 -- cgit v1.2.3 From 781fe631fafda37402abdbc4647698a107e2284d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:15 +0200 Subject: selftests: forwarding: Allow to get netdev interfaces names from commandline Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 083a16eb7803..3385ba76ac19 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -45,6 +45,21 @@ if [[ ! -v NUM_NETIFS ]]; then exit 0 fi +############################################################################## +# Command line options handling + +count=0 + +while [[ $# -gt 0 ]]; do + if [[ "$count" -eq "0" ]]; then + unset NETIFS + declare -A NETIFS + fi + count=$((count + 1)) + NETIFS[p$count]="$1" + shift +done + ############################################################################## # Network interfaces configuration -- cgit v1.2.3 From 07e5c75184a11c46eddb08f2435ba4f3e7152e62 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:16 +0200 Subject: selftests: forwarding: Introduce tc flower matching tests Add first part of flower tests. This patch only contains dst/src ip/mac matching. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_common.sh | 23 +++ .../testing/selftests/net/forwarding/tc_flower.sh | 196 +++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 tools/testing/selftests/net/forwarding/tc_common.sh create mode 100755 tools/testing/selftests/net/forwarding/tc_flower.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_common.sh b/tools/testing/selftests/net/forwarding/tc_common.sh new file mode 100644 index 000000000000..acd0b520241c --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_common.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +tc_check_packets() +{ + local id=$1 + local handle=$2 + local count=$3 + local ret + + output="$(tc -j -s filter show $id)" + # workaround the jq bug which causes jq to return 0 in case input is "" + ret=$? + if [[ $ret -ne 0 ]]; then + return $ret + fi + echo $output | \ + jq -e ".[] \ + | select(.options.handle == $handle) \ + | select(.options.actions[0].stats.packets == $count)" \ + &> /dev/null + return $? +} diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh new file mode 100755 index 000000000000..026a4ea4b2fb --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower.sh @@ -0,0 +1,196 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=2 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 198.51.100.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 198.51.100.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24 +} + +match_dst_mac_test() +{ + local dummy_mac=de:ad:be:ef:aa:aa + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_mac $dummy_mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_mac $h2mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "dst_mac match ($tcflags)" +} + +match_src_mac_test() +{ + local dummy_mac=de:ad:be:ef:aa:aa + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags src_mac $dummy_mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags src_mac $h1mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "src_mac match ($tcflags)" +} + +match_dst_ip_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 198.51.100.2 action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct filter with mask" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "dst_ip match ($tcflags)" +} + +match_src_ip_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags src_ip 198.51.100.1 action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags src_ip 192.0.2.1 action drop + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags src_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct filter with mask" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "src_ip match ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +match_dst_mac_test +match_src_mac_test +match_dst_ip_test +match_src_ip_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + match_dst_mac_test + match_src_mac_test + match_dst_ip_test + match_src_ip_test +fi + +exit $EXIT_STATUS -- cgit v1.2.3 From bc13af291ebba244226b12e75d36a6eb6373a5d6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:17 +0200 Subject: selftests: forwarding: Introduce tc actions tests Add first part of actions tests. This patch only contains tests of gact ok/drop/trap and mirred redirect egress. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_actions.sh | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_actions.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh new file mode 100755 index 000000000000..84234317a25d --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -0,0 +1,195 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/24 + tc qdisc add dev $swp1 clsact + + simple_if_init $swp2 192.0.2.1/24 +} + +switch_destroy() +{ + simple_if_fini $swp2 192.0.2.1/24 + + tc qdisc del dev $swp1 clsact + simple_if_fini $swp1 192.0.2.2/24 +} + +mirred_egress_redirect_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched without redirect rule inserted" + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + dev $swp2 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match incoming redirected packet" + + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + log_test "mirred egress redirect ($tcflags)" +} + +gact_drop_and_ok_test() +{ + RET=0 + + tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ + skip_hw dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 102 1 + check_err $? "Packet was not dropped" + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action ok + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 101 1 + check_err $? "Did not see trapped packet" + + tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + + log_test "gact drop and ok ($tcflags)" +} + +gact_trap_test() +{ + RET=0 + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + skip_hw dst_ip 192.0.2.2 action drop + tc filter add dev $swp1 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + dev $swp2 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 101 1 + check_fail $? "Saw packet without trap rule inserted" + + tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action trap + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 102 1 + check_err $? "Packet was not trapped" + + tc_check_packets "dev $swp1 ingress" 101 1 + check_err $? "Did not see trapped packet" + + tc filter del dev $swp1 ingress protocol ip pref 3 handle 103 flower + tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + + log_test "trap ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + swp1origmac=$(mac_get $swp1) + swp2origmac=$(mac_get $swp2) + ip link set $swp1 address $h2mac + ip link set $swp2 address $h1mac + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup + + ip link set $swp2 address $swp2origmac + ip link set $swp1 address $swp1origmac +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +gact_drop_and_ok_test +mirred_egress_redirect_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + gact_drop_and_ok_test + mirred_egress_redirect_test + gact_trap_test +fi + +exit $EXIT_STATUS -- cgit v1.2.3 From b13f245e844d1535597298ac0f0f0a94f56c239b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:18 +0200 Subject: selftests: forwarding: Introduce basic tc chains tests Tests chains matching and goto chain action. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_chains.sh | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_chains.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh new file mode 100755 index 000000000000..94c114ad8b44 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_chains.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=2 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 +} + +unreachable_chain_test() +{ + RET=0 + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower $tcflags dst_mac $h2mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 1101 1 + check_fail $? "matched on filter in unreachable chain" + + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower + + log_test "unreachable chain ($tcflags)" +} + +gact_goto_chain_test() +{ + RET=0 + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower $tcflags dst_mac $h2mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_mac $h2mac action drop + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_mac $h2mac action goto chain 1 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct filter with goto chain action" + + tc_check_packets "dev $h2 ingress" 1101 1 + check_err $? "Did not match on correct filter in chain 1" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower + + log_test "gact goto chain ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +unreachable_chain_test +gact_goto_chain_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + unreachable_chain_test + gact_goto_chain_test +fi + +exit $EXIT_STATUS -- cgit v1.2.3 From 4908e24b812d74d0534e8b33edd58417aefa93d0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:19 +0200 Subject: selftests: forwarding: Introduce basic shared blocks tests Test shared block infrastructure. This is a basic test that shares TC block in between 2 clsact qdiscs. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 6 + .../selftests/net/forwarding/tc_shblocks.sh | 122 +++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_shblocks.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 3385ba76ac19..23866a685f77 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -30,6 +30,12 @@ if [[ $? -ne 0 ]]; then exit 0 fi +tc filter help 2>&1 | grep block &> /dev/null +if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old, missing shared block support" + exit 0 +fi + if [[ ! -x "$(command -v jq)" ]]; then echo "SKIP: jq not installed" exit 0 diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh new file mode 100755 index 000000000000..cfc8a2ace388 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.1/24 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.1/24 +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/24 + tc qdisc add dev $swp1 ingress_block 22 egress_block 23 clsact + + simple_if_init $swp2 192.0.2.2/24 + tc qdisc add dev $swp2 ingress_block 22 egress_block 23 clsact +} + +switch_destroy() +{ + tc qdisc del dev $swp2 clsact + simple_if_fini $swp2 192.0.2.2/24 + + tc qdisc del dev $swp1 clsact + simple_if_fini $swp1 192.0.2.2/24 +} + +shared_block_test() +{ + RET=0 + + tc filter add block 22 protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "block 22" 101 1 + check_err $? "Did not match first incoming packet on a block" + + $MZ $h2 -c 1 -p 64 -a $h2mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "block 22" 101 2 + check_err $? "Did not match second incoming packet on a block" + + tc filter del block 22 protocol ip pref 1 handle 101 flower + + log_test "shared block ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + swmac=$(mac_get $swp1) + swp2origmac=$(mac_get $swp2) + ip link set $swp2 address $swmac + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup + + ip link set $swp2 address $swp2origmac +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +shared_block_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + shared_block_test +fi + +exit $EXIT_STATUS -- cgit v1.2.3 From 198979be6c16aa62025d5a47680f2c7849b7e64c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:30 -0800 Subject: selftests: forwarding: Only check tc version for tc tests Capabilities of tc command are irrelevant for router tests: $ ./router.sh SKIP: iproute2 too old, missing shared block support Add a CHECK_TC flag and only check tc capabilities if set. Add flag to tc_common.sh and have it sourced before lib.sh Also, if the command lacks some feature the test should exit non-0. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 1 + tools/testing/selftests/net/forwarding/lib.sh | 29 ++++++++++++++-------- .../testing/selftests/net/forwarding/tc_actions.sh | 2 +- .../testing/selftests/net/forwarding/tc_chains.sh | 2 +- .../testing/selftests/net/forwarding/tc_common.sh | 2 ++ .../testing/selftests/net/forwarding/tc_flower.sh | 2 +- .../selftests/net/forwarding/tc_shblocks.sh | 2 +- 7 files changed, 25 insertions(+), 15 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index 651998e70557..75d922438bc9 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 +CHECK_TC="yes" source lib.sh h1_create() diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 23866a685f77..d0af52109360 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -19,26 +19,33 @@ fi ############################################################################## # Sanity checks +check_tc_version() +{ + tc -j &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old; tc is missing JSON support" + exit 1 + fi + + tc filter help 2>&1 | grep block &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old; tc is missing shared block support" + exit 1 + fi +} + if [[ "$(id -u)" -ne 0 ]]; then echo "SKIP: need root privileges" exit 0 fi -tc -j &> /dev/null -if [[ $? -ne 0 ]]; then - echo "SKIP: iproute2 too old, missing JSON support" - exit 0 -fi - -tc filter help 2>&1 | grep block &> /dev/null -if [[ $? -ne 0 ]]; then - echo "SKIP: iproute2 too old, missing shared block support" - exit 0 +if [[ "$CHECK_TC" = "yes" ]]; then + check_tc_version fi if [[ ! -x "$(command -v jq)" ]]; then echo "SKIP: jq not installed" - exit 0 + exit 1 fi if [[ ! -x "$(command -v $MZ)" ]]; then diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 84234317a25d..8ab5cf0a960b 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh index 94c114ad8b44..2fd15226974b 100755 --- a/tools/testing/selftests/net/forwarding/tc_chains.sh +++ b/tools/testing/selftests/net/forwarding/tc_chains.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=2 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_common.sh b/tools/testing/selftests/net/forwarding/tc_common.sh index acd0b520241c..9d3b64a2a264 100644 --- a/tools/testing/selftests/net/forwarding/tc_common.sh +++ b/tools/testing/selftests/net/forwarding/tc_common.sh @@ -1,6 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +CHECK_TC="yes" + tc_check_packets() { local id=$1 diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh index 026a4ea4b2fb..032b882adfc0 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=2 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh index cfc8a2ace388..077b98048ef4 100755 --- a/tools/testing/selftests/net/forwarding/tc_shblocks.sh +++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" -- cgit v1.2.3 From 5ee0902a0d584bd765165448fec8bb1409d5d027 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:31 -0800 Subject: selftests: forwarding: Handle 0 for packet difference in multipath tests If the packet stats have a difference of 0, the test output shows: INFO: Expected ratio 2.00 Measured ratio Runtime error (func=(main), adr=9): Divide by zero (standard_in) 2: syntax error (standard_in) 1: syntax error ./router_multipath.sh: line 187: test: : integer expression expected TEST: Multipath [FAIL] Too large discrepancy between expected and measured ratios Handle the 0 and display a cleaner message: INFO: Running IPv6 multipath tests TEST: Multipath [FAIL] Packet difference is 0 Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_multipath.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index d31888e3133e..c1a437c5b15f 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -168,6 +168,13 @@ multipath_eval() RET=0 + if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then + check_err 1 "Packet difference is 0" + log_test "Multipath" + log_info "Expected ratio $weights_ratio" + return + fi + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ | bc -l) -- cgit v1.2.3 From 993d337c242e292dca89de4558dd8ebfc216fc83 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:32 -0800 Subject: selftests: forwarding: Use PING6 instead of ping for ipv6 multipath test On Debian jessie ping can not handle IPv6 addresses so the command fails. Use PING6 which is set to ping6. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_multipath.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index c1a437c5b15f..745fb40bfa44 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -249,7 +249,7 @@ multipath6_test() # Generate 16384 echo requests, each with a random flow label. for _ in $(seq 1 16384); do - ip vrf exec vrf-h1 ping 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null + ip vrf exec vrf-h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null done t1_rp12=$(link_stats_tx_packets_get $rp12) -- cgit v1.2.3 From 36b4c0adad2662464a5a392b592311524bd3a854 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:33 -0800 Subject: selftests: forwarding: Add description to the multipath tests Add a better description to the summary for multipath tests. e.g., INFO: Running IPv6 multipath tests TEST: ECMP [PASS] INFO: Expected ratio 1.00 Measured ratio 1.02 TEST: Weighted MP 2:1 [PASS] INFO: Expected ratio 2.00 Measured ratio 2.02 TEST: Weighted MP 11:45 [PASS] INFO: Expected ratio 4.09 Measured ratio 4.03 Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 37 ++++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 745fb40bfa44..55595305a604 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -160,10 +160,11 @@ router2_destroy() multipath_eval() { - local weight_rp12=$1 - local weight_rp13=$2 - local packets_rp12=$3 - local packets_rp13=$4 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 + local packets_rp12=$4 + local packets_rp13=$5 local weights_ratio packets_ratio diff RET=0 @@ -192,14 +193,15 @@ multipath_eval() test "$(echo "$diff / $weights_ratio > 0.1" | bc -l)" -eq 0 check_err $? "Too large discrepancy between expected and measured ratios" - log_test "Multipath" + log_test "$desc" log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" } multipath4_test() { - local weight_rp12=$1 - local weight_rp13=$2 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 local t0_rp12 t0_rp13 t1_rp12 t1_rp13 local packets_rp12 packets_rp13 local hash_policy @@ -224,7 +226,7 @@ multipath4_test() let "packets_rp12 = $t1_rp12 - $t0_rp12" let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 # Restore settings. ip route replace 198.51.100.0/24 vrf vrf-r1 \ @@ -235,8 +237,9 @@ multipath4_test() multipath6_test() { - local weight_rp12=$1 - local weight_rp13=$2 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 local t0_rp12 t0_rp13 t1_rp12 t1_rp13 local packets_rp12 packets_rp13 @@ -257,7 +260,7 @@ multipath6_test() let "packets_rp12 = $t1_rp12 - $t0_rp12" let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 ip route replace 2001:db8:2::/64 vrf vrf-r1 \ nexthop via fe80:2::22 dev $rp12 \ @@ -267,14 +270,14 @@ multipath6_test() multipath_test() { log_info "Running IPv4 multipath tests" - multipath4_test 1 1 - multipath4_test 2 1 - multipath4_test 11 45 + multipath4_test "ECMP" 1 1 + multipath4_test "Weighted MP 2:1" 2 1 + multipath4_test "Weighted MP 11:45" 11 45 log_info "Running IPv6 multipath tests" - multipath6_test 1 1 - multipath6_test 2 1 - multipath6_test 11 45 + multipath6_test "ECMP" 1 1 + multipath6_test "Weighted MP 2:1" 2 1 + multipath6_test "Weighted MP 11:45" 11 45 } setup_prepare() -- cgit v1.2.3 From 91a5c1ecba9f23f247b3772e6d54aabfebc0e300 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 2 Mar 2018 08:32:21 -0800 Subject: selftests: forwarding: Add multipath test for L4 hashing Add IPv6 multipath test using L4 hashing. Created with inputs from Ido Schimmel. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 55595305a604..3bc351008db6 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -235,6 +235,45 @@ multipath4_test() sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy } +multipath6_l4_test() +{ + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + local hash_policy + + # Transmit multiple flows from h1 to h2 and make sure they are + # distributed between both multipath links (rp12 and rp13) + # according to the configured weights. + hash_policy=$(sysctl -n net.ipv6.fib_multipath_hash_policy) + sysctl -q -w net.ipv6.fib_multipath_hash_policy=1 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 weight $weight_rp12 \ + nexthop via fe80:3::23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + $MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \ + -d 1msec -t udp "sp=1024,dp=0-32768" + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 + + sysctl -q -w net.ipv6.fib_multipath_hash_policy=$hash_policy +} + multipath6_test() { local desc="$1" @@ -278,6 +317,11 @@ multipath_test() multipath6_test "ECMP" 1 1 multipath6_test "Weighted MP 2:1" 2 1 multipath6_test "Weighted MP 11:45" 11 45 + + log_info "Running IPv6 L4 hash multipath tests" + multipath6_l4_test "ECMP" 1 1 + multipath6_l4_test "Weighted MP 2:1" 2 1 + multipath6_l4_test "Weighted MP 11:45" 11 45 } setup_prepare() -- cgit v1.2.3 From efab163bbc19e5dbd2b7756c1f26defc9c27d6ba Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 28 Feb 2018 15:36:19 -0500 Subject: tools: tc-testing: Add notap option Add a command line arg to suppress tap output. Handy in case all the tap output is being supplied by the plugins. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 7b50775abaf6..241eea37e4a4 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -241,12 +241,17 @@ def test_runner(pm, args, filtered_tests): testlist = filtered_tests tcount = len(testlist) index = 1 - tap = str(index) + ".." + str(tcount) + "\n" + tap = '' badtest = None stage = None emergency_exit = False emergency_exit_message = '' + if args.notap: + if args.verbose: + tap = 'notap requested: omitting test plan\n' + else: + tap = str(index) + ".." + str(tcount) + "\n" try: pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) except Exception as ee: @@ -303,15 +308,16 @@ def test_runner(pm, args, filtered_tests): # if we failed in setup or teardown, # fill in the remaining tests with ok-skipped count = index - tap += 'about to flush the tap output if tests need to be skipped\n' - if tcount + 1 != index: - for tidx in testlist[index - 1:]: - msg = 'skipped - previous {} failed'.format(stage) - tap += 'ok {} - {} # {} {} {}\n'.format( - count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) - count += 1 - - tap += 'done flushing skipped test tap output\n' + if not args.notap: + tap += 'about to flush the tap output if tests need to be skipped\n' + if tcount + 1 != index: + for tidx in testlist[index - 1:]: + msg = 'skipped - previous {} failed'.format(stage) + tap += 'ok {} - {} # {} {} {}\n'.format( + count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) + count += 1 + + tap += 'done flushing skipped test tap output\n' pm.call_post_suite(index) return tap @@ -389,6 +395,9 @@ def set_args(parser): parser.add_argument( '-v', '--verbose', action='count', default=0, help='Show the commands that are being run') + parser.add_argument( + '-N', '--notap', action='store_true', + help='Suppress tap results for command under test') parser.add_argument('-d', '--device', help='Execute the test case in flower category') return parser @@ -601,7 +610,10 @@ def set_operation_mode(pm, args): catresults = test_runner(pm, args, alltests) else: catresults = 'No tests found\n' - print('All test results: \n\n{}'.format(catresults)) + if args.notap: + print('Tap output suppression requested\n') + else: + print('All test results: \n\n{}'.format(catresults)) def main(): """ -- cgit v1.2.3 From 053533fc7577ddbe14b2a7c4a8fc70ce3fbb3547 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Fri, 2 Mar 2018 11:22:20 +0900 Subject: selftests: rtnetlink: remove testns on test fail This patch removes testns after test failure so that next test can continue with clean ns Signed-off-by: Prashant Bhole Acked-by: William Tu Signed-off-by: David S. Miller --- tools/testing/selftests/net/rtnetlink.sh | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index a622eeecc3a6..e6f485235435 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -517,6 +517,7 @@ kci_test_gretap() ip link help gretap 2>&1 | grep -q "^Usage:" if [ $? -ne 0 ];then echo "SKIP: gretap: iproute2 too old" + ip netns del "$testns" return 1 fi @@ -543,6 +544,7 @@ kci_test_gretap() if [ $ret -ne 0 ]; then echo "FAIL: gretap" + ip netns del "$testns" return 1 fi echo "PASS: gretap" @@ -565,6 +567,7 @@ kci_test_ip6gretap() ip link help ip6gretap 2>&1 | grep -q "^Usage:" if [ $? -ne 0 ];then echo "SKIP: ip6gretap: iproute2 too old" + ip netns del "$testns" return 1 fi @@ -591,6 +594,7 @@ kci_test_ip6gretap() if [ $ret -ne 0 ]; then echo "FAIL: ip6gretap" + ip netns del "$testns" return 1 fi echo "PASS: ip6gretap" @@ -655,6 +659,7 @@ kci_test_erspan() if [ $ret -ne 0 ]; then echo "FAIL: erspan" + ip netns del "$testns" return 1 fi echo "PASS: erspan" @@ -720,6 +725,7 @@ kci_test_ip6erspan() if [ $ret -ne 0 ]; then echo "FAIL: ip6erspan" + ip netns del "$testns" return 1 fi echo "PASS: ip6erspan" -- cgit v1.2.3 From 200066a5bdcc2d4527562ee3760d405b6ec5b5d5 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Sun, 4 Mar 2018 16:35:26 +0200 Subject: selftests: Extend the tc action test for action mirror Currently the tc action test is used only to test mirred redirect action. This patch extends it for mirred mirror. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: Arkadi Sharshevsky Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 8ab5cf0a960b..6b18ba2d3982 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -45,8 +45,10 @@ switch_destroy() simple_if_fini $swp1 192.0.2.2/24 } -mirred_egress_redirect_test() +mirred_egress_test() { + local action=$1 + RET=0 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ @@ -59,19 +61,19 @@ mirred_egress_redirect_test() check_fail $? "Matched without redirect rule inserted" tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ - $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + $tcflags dst_ip 192.0.2.2 action mirred egress $action \ dev $swp2 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ -t ip -q tc_check_packets "dev $h2 ingress" 101 1 - check_err $? "Did not match incoming redirected packet" + check_err $? "Did not match incoming $action packet" tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower - log_test "mirred egress redirect ($tcflags)" + log_test "mirred egress $action ($tcflags)" } gact_drop_and_ok_test() @@ -180,7 +182,8 @@ setup_prepare setup_wait gact_drop_and_ok_test -mirred_egress_redirect_test +mirred_egress_test "redirect" +mirred_egress_test "mirror" tc_offload_check if [[ $? -ne 0 ]]; then @@ -188,7 +191,8 @@ if [[ $? -ne 0 ]]; then else tcflags="skip_sw" gact_drop_and_ok_test - mirred_egress_redirect_test + mirred_egress_test "redirect" + mirred_egress_test "mirror" gact_trap_test fi -- cgit v1.2.3 From 190f887c3cd0d07e53a7d44162c951451f4f5528 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 4 Mar 2018 17:37:47 -0800 Subject: selftests: forwarding: Add suppport to create veth interfaces For tests using veth interfaces, the test infrastructure can create the netdevs if they do not exist. Arguably this is a preferred approach since the tests require p$N and p$(N+1) to be pairs. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- .../net/forwarding/forwarding.config.sample | 5 ++++ tools/testing/selftests/net/forwarding/lib.sh | 35 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample index ab235c124f20..df54c9eb5100 100644 --- a/tools/testing/selftests/net/forwarding/forwarding.config.sample +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -14,6 +14,11 @@ NETIFS[p6]=veth5 NETIFS[p7]=veth6 NETIFS[p8]=veth7 +NETIF_TYPE=veth + +# only virtual interfaces (veth) can be created by test infra +#NETIF_CREATE=yes + ############################################################################## # Defines diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index d0af52109360..273511ef2b43 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -76,6 +76,41 @@ done ############################################################################## # Network interfaces configuration +create_netif_veth() +{ + local i + + for i in $(eval echo {1..$NUM_NETIFS}); do + local j=$((i+1)) + + ip link show dev ${NETIFS[p$i]} &> /dev/null + if [[ $? -ne 0 ]]; then + ip link add ${NETIFS[p$i]} type veth \ + peer name ${NETIFS[p$j]} + if [[ $? -ne 0 ]]; then + echo "Failed to create netif" + exit 1 + fi + fi + i=$j + done +} + +create_netif() +{ + case "$NETIF_TYPE" in + veth) create_netif_veth + ;; + *) echo "Can not create interfaces of type \'$NETIF_TYPE\'" + exit 1 + ;; + esac +} + +if [[ "$NETIF_CREATE" = "yes" ]]; then + create_netif +fi + for i in $(eval echo {1..$NUM_NETIFS}); do ip link show dev ${NETIFS[p$i]} &> /dev/null if [[ $? -ne 0 ]]; then -- cgit v1.2.3 From 4d1e46a55ea9f8d693ceabe1ba4b056e55fb6625 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 6 Mar 2018 17:31:32 +0900 Subject: selftests/net: fix in_netns.sh script execute the subprocess in netns using 'ip netns exec' Fixes: cc30c93fa020 ("selftests/net: ignore background traffic in psock_fanout") Signed-off-by: Prashant Bhole Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/in_netns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/in_netns.sh b/tools/testing/selftests/net/in_netns.sh index f57a2eaad069..88795b510b32 100755 --- a/tools/testing/selftests/net/in_netns.sh +++ b/tools/testing/selftests/net/in_netns.sh @@ -19,5 +19,5 @@ cleanup() { trap cleanup EXIT setup -"$@" +ip netns exec "${NETNS}" "$@" exit "$?" -- cgit v1.2.3 From d1f1b9cbf34c667d06adc44136e448cade8e28d9 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 6 Mar 2018 22:16:27 +0100 Subject: selftests: net: Introduce first PMTU test One single test implemented so far: test_pmtu_vti6_exception checks that the PMTU of a route exception, caused by a tunnel exceeding the link layer MTU, is affected by administrative changes of the tunnel MTU. Creation of the route exception is checked too. Requested-by: David Ahern Signed-off-by: Stefano Brivio Acked-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 2 +- tools/testing/selftests/net/pmtu.sh | 163 +++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/net/pmtu.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 229a038966e3..785fc18a16b4 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh fib-onlink-tests.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh new file mode 100755 index 000000000000..6c19c148cef8 --- /dev/null +++ b/tools/testing/selftests/net/pmtu.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Check that route PMTU values match expectations +# +# Tests currently implemented: +# +# - test_pmtu_vti6_exception +# Set up vti6 tunnel on top of veth, with xfrm states and policies, in two +# namespaces with matching endpoints. Check that route exception is +# created by exceeding link layer MTU with ping to other endpoint. Then +# decrease and increase MTU of tunnel, checking that route exception PMTU +# changes accordingly + +NS_A="ns-$(mktemp -u XXXXXX)" +NS_B="ns-$(mktemp -u XXXXXX)" +ns_a="ip netns exec ${NS_A}" +ns_b="ip netns exec ${NS_B}" + +veth6_a_addr="fd00:1::a" +veth6_b_addr="fd00:1::b" +veth6_mask="64" + +vti6_a_addr="fd00:2::a" +vti6_b_addr="fd00:2::b" +vti6_mask="64" + +setup_namespaces() { + ip netns add ${NS_A} || return 0 + ip netns add ${NS_B} + + return 1 +} + +setup_veth() { + ${ns_a} ip link add veth_a type veth peer name veth_b || return 0 + ${ns_a} ip link set veth_b netns ${NS_B} + + ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a + ${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b + + ${ns_a} ip link set veth_a up + ${ns_b} ip link set veth_b up + + return 1 +} + +setup_vti6() { + ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 0 + ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 + + ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a + ${ns_b} ip addr add ${vti6_b_addr}/${vti6_mask} dev vti_b + + ${ns_a} ip link set vti_a up + ${ns_b} ip link set vti_b up + + sleep 1 + + return 1 +} + +setup_xfrm() { + ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 0 + ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel + + ${ns_b} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel + ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + + return 1 +} + +setup() { + tunnel_type="$1" + + [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 + + setup_namespaces && echo "SKIP: namespaces not supported" && exit 0 + setup_veth && echo "SKIP: veth not supported" && exit 0 + + case ${tunnel_type} in + "vti6") + setup_vti6 && echo "SKIP: vti6 not supported" && exit 0 + setup_xfrm && echo "SKIP: xfrm not supported" && exit 0 + ;; + *) + ;; + esac +} + +cleanup() { + ip netns del ${NS_A} 2 > /dev/null + ip netns del ${NS_B} 2 > /dev/null +} + +mtu() { + ns_cmd="${1}" + dev="${2}" + mtu="${3}" + + ${ns_cmd} ip link set dev ${dev} mtu ${mtu} +} + +route_get_dst_exception() { + dst="${1}" + + ${ns_a} ip route get "${dst}" +} + +route_get_dst_pmtu_from_exception() { + dst="${1}" + + exception="$(route_get_dst_exception ${dst})" + next=0 + for i in ${exception}; do + [ ${next} -eq 1 ] && echo "${i}" && return + [ "${i}" = "mtu" ] && next=1 + done +} + +test_pmtu_vti6_exception() { + setup vti6 + + # Create route exception by exceeding link layer MTU + mtu "${ns_a}" veth_a 4000 + mtu "${ns_b}" veth_b 4000 + mtu "${ns_a}" vti_a 5000 + mtu "${ns_b}" vti_b 5000 + ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null + + # Check that exception was created + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" = "" ]; then + echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" + exit 1 + fi + + # Decrease tunnel MTU, check for PMTU decrease in route exception + mtu "${ns_a}" vti_a 3000 + + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 3000 ]; then + echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" + exit 1 + fi + + # Increase tunnel MTU, check for PMTU increase in route exception + mtu "${ns_a}" vti_a 9000 + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 9000 ]; then + echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" + exit 1 + fi + + echo "PASS" +} + +trap cleanup EXIT + +test_pmtu_vti6_exception + +exit 0 -- cgit v1.2.3 From 0c17db05ec982607121b8f01cf4ce03513964d9c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 7 Mar 2018 13:57:59 +0100 Subject: selftests: forwarding: fix "ok" action test Fix the "ok" action test so it checks that packet that is okayed does not continue to be processed by other rules. Fix error message as well. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 6b18ba2d3982..ac6b6a1057d8 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -96,7 +96,10 @@ gact_drop_and_ok_test() -t ip -q tc_check_packets "dev $swp1 ingress" 101 1 - check_err $? "Did not see trapped packet" + check_err $? "Did not see passed packet" + + tc_check_packets "dev $swp1 ingress" 102 2 + check_fail $? "Packet was dropped and it should not reach here" tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower -- cgit v1.2.3 From dff58a09d77e152056a4803ff89b6ec3fc6c9b2c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 7 Mar 2018 13:58:00 +0100 Subject: selftests: forwarding: fix flags passed to first drop rule in gact_drop_and_ok_test Fix copy&paste error and pass proper flags. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index ac6b6a1057d8..3a6385ebd5d0 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -81,7 +81,7 @@ gact_drop_and_ok_test() RET=0 tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ - skip_hw dst_ip 192.0.2.2 action drop + $tcflags dst_ip 192.0.2.2 action drop $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ -t ip -q -- cgit v1.2.3 From dcf1bcb6aed7785ccb098163cca5a2f9e4175663 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 8 Mar 2018 11:17:23 +0100 Subject: selftests/net: enable fragments for fib-onlink-tests We miss CONFIG_* fragments so test fib-onlink-tests.sh can do: ip li add lisa type vrf table 1101 ip li add veth1 type veth peer name veth2 And the follow message occurs if it isn't enabled: Configuring interfaces RTNETLINK answers: Operation not supported This enables for NET_NRF (and friends) and VETH so we can create a vrf table and veth. Fixes: 153e1b84f477 ("selftests: Add FIB onlink tests") Signed-off-by: Anders Roxell Signed-off-by: David S. Miller --- tools/testing/selftests/net/config | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 7177bea1fdfa..6a75a3ea44ad 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -2,3 +2,8 @@ CONFIG_USER_NS=y CONFIG_BPF_SYSCALL=y CONFIG_TEST_BPF=m CONFIG_NUMA=y +CONFIG_NET_VRF=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_IPV6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_VETH=y -- cgit v1.2.3 From 8edfaf7d33983309b30564e2abaede26163764f3 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 8 Mar 2018 14:56:43 -0500 Subject: tc-testing: add csum tests Signed-off-by: Roman Mashak Tested-by: Davide Caratti Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/csum.json | 410 +++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/csum.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json new file mode 100644 index 000000000000..93cf8fea8ae7 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json @@ -0,0 +1,410 @@ +[ + { + "id": "6d84", + "name": "Add csum iph action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum iph index 800", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 800", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 800 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "1862", + "name": "Add csum ip4h action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ip4h index 7", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 7", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 7 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "15c6", + "name": "Add csum ipv4h action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ipv4h index 1122", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 1122", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 1122 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bf47", + "name": "Add csum icmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum icmp index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 1", + "matchPattern": "action order [0-9]*: csum \\(icmp\\) action pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "cc1d", + "name": "Add csum igmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum igmp index 999", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 999", + "matchPattern": "action order [0-9]*: csum \\(igmp\\) action pass.*index 999 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bccc", + "name": "Add csum foobar action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum foobar index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "action order [0-9]*: csum \\(foobar\\) action pass.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "3bb4", + "name": "Add csum tcp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum tcp index 9999", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 9999", + "matchPattern": "action order [0-9]*: csum \\(tcp\\) action pass.*index 9999 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "759c", + "name": "Add csum udp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp index 334455", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 334455", + "matchPattern": "action order [0-9]*: csum \\(udp\\) action pass.*index 334455 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bdb6", + "name": "Add csum udp xor iph action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp xor iph index 3", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "action order [0-9]*: csum \\(udp xor iph\\) action pass.*index 3 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "c220", + "name": "Add csum udplite action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udplite continue index 3", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 3", + "matchPattern": "action order [0-9]*: csum \\(udplite\\) action continue.*index 3 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "8993", + "name": "Add csum sctp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum sctp index 777", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 777", + "matchPattern": "action order [0-9]*: csum \\(sctp\\) action pass.*index 777 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "b138", + "name": "Add csum ip & icmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ip and icmp pipe index 123", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 123", + "matchPattern": "action order [0-9]*: csum \\(iph, icmp\\) action pipe.*index 123 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "eeda", + "name": "Add csum ip & sctp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ipv4h sctp continue index 2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 2", + "matchPattern": "action order [0-9]*: csum \\(iph, sctp\\) action continue.*index 2 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "0017", + "name": "Add csum udp or tcp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp or tcp continue index 27", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 27", + "matchPattern": "action order [0-9]*: csum \\(tcp, udp\\) action continue.*index 27 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "ce92", + "name": "Add csum udp action with cookie", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp pipe index 7 cookie 12345678", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 7", + "matchPattern": "action order [0-9]*: csum \\(udp\\) action pipe.*index 7.*cookie 12345678", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "912f", + "name": "Add csum icmp action with large cookie", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum icmp pipe index 17 cookie aabbccddeeff1122", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 17", + "matchPattern": "action order [0-9]*: csum \\(icmp\\) action pipe.*index 17.*cookie aabbccddeeff1122", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "879b", + "name": "Add batch of 32 csum tcp actions", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action csum tcp continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "^[ \t]+index [0-9]* ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action csum" + ] + } +] -- cgit v1.2.3 From 75291f3a6b86a53f2607658de3b8b267e306bf60 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Thu, 8 Mar 2018 15:27:44 -0500 Subject: tools: tc-testing: Can refer to $TESTID in test spec When processing the commands in the test cases, substitute the test id for $TESTID. This helps to make more flexible tests. For example, the testid can be given as a command line argument. As an example, if we wish to save the test output to a file named for the test case, we can write in the test case: "cmdUnderTest": "some test command | tee -a $TESTID.out" Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 241eea37e4a4..c05b9f0f3db2 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -177,6 +177,7 @@ def prepare_env(args, pm, stage, prefix, cmdlist, output = None): '"{}" did not complete successfully'.format(prefix)) def run_one_test(pm, args, index, tidx): + global NAMES result = True tresult = "" tap = "" @@ -184,6 +185,9 @@ def run_one_test(pm, args, index, tidx): print("\t====================\n=====> ", end="") print("Test " + tidx["id"] + ": " + tidx["name"]) + # populate NAMES with TESTID for this test + NAMES['TESTID'] = tidx['id'] + pm.call_pre_case(index, tidx['id']) prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"]) @@ -227,6 +231,8 @@ def run_one_test(pm, args, index, tidx): index += 1 + # remove TESTID from NAMES + del(NAMES['TESTID']) return tap def test_runner(pm, args, filtered_tests): -- cgit v1.2.3 From 2b3905de8b3d8511aee1d4acbf063197291cdd3f Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Thu, 8 Mar 2018 15:28:03 -0500 Subject: tools: tc-testing: Can pause just before post-suite With option -P, the test script will pause just before the post_suite functions are called. This allows the tester to inspect the system before it is torn down. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index c05b9f0f3db2..44de4a272a11 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -324,6 +324,12 @@ def test_runner(pm, args, filtered_tests): count += 1 tap += 'done flushing skipped test tap output\n' + + if args.pause: + print('Want to pause\nPress enter to continue ...') + if input(sys.stdin): + print('got something on stdin') + pm.call_post_suite(index) return tap @@ -406,6 +412,9 @@ def set_args(parser): help='Suppress tap results for command under test') parser.add_argument('-d', '--device', help='Execute the test case in flower category') + parser.add_argument( + '-P', '--pause', action='store_true', + help='Pause execution just before post-suite stage') return parser -- cgit v1.2.3 From 3a021ab56468db57868a9bc6721b7dfbec672a15 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:22 +0200 Subject: selftests: forwarding: Add a test for VLAN-unaware bridge Similar to the VLAN-aware bridge test, test the VLAN-unaware bridge and make sure that ping, FDB learning and flooding work as expected. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- .../net/forwarding/bridge_vlan_unaware.sh | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh new file mode 100755 index 000000000000..1cddf06f691d --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +switch_create() +{ + # 10 Seconds ageing time. + ip link add dev br0 type bridge ageing_time 1000 mcast_snooping 0 + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + + ip link set dev br0 up + ip link set dev $swp1 up + ip link set dev $swp2 up +} + +switch_destroy() +{ + ip link set dev $swp2 down + ip link set dev $swp1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 192.0.2.2 +ping6_test $h1 2001:db8:1::2 +learning_test "br0" $swp1 $h1 $h2 +flood_test $swp2 $h1 $h2 + +exit $EXIT_STATUS -- cgit v1.2.3 From ff0162af9e7b2e33d4d40f41130c65ba416ba059 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:23 +0200 Subject: selftests: forwarding: Exit with error when missing dependencies We already return an error when some dependencies (e.g., 'jq') are missing so lets be consistent and do that for all. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 273511ef2b43..6ac8a98fa270 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -50,7 +50,7 @@ fi if [[ ! -x "$(command -v $MZ)" ]]; then echo "SKIP: $MZ not installed" - exit 0 + exit 1 fi if [[ ! -v NUM_NETIFS ]]; then -- cgit v1.2.3 From 231b85abaaeef119811a9f036245c94bd5483415 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:24 +0200 Subject: selftests: forwarding: Exit with error when missing interfaces Returning 0 gives a false sense of success when the required modules did not even manage to be initialized and register the required net devices. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 6ac8a98fa270..e989d8a1d4fb 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -55,7 +55,7 @@ fi if [[ ! -v NUM_NETIFS ]]; then echo "SKIP: importer does not define \"NUM_NETIFS\"" - exit 0 + exit 1 fi ############################################################################## @@ -115,7 +115,7 @@ for i in $(eval echo {1..$NUM_NETIFS}); do ip link show dev ${NETIFS[p$i]} &> /dev/null if [[ $? -ne 0 ]]; then echo "SKIP: could not find all required interfaces" - exit 0 + exit 1 fi done -- cgit v1.2.3 From 59be45c375e6decce4216dc85fcc8ddf46d38c68 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:25 +0200 Subject: selftests: forwarding: Allow creation of interfaces without a config file Some users want to be able to run the tests without a configuration file which is useful when one needs to test both virtual and physical interfaces on the same machine. Move the defines that set the type of interface to create and whether to create it away from the optional configuration file to the library like the rest of the defines. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/forwarding.config.sample | 9 ++++----- tools/testing/selftests/net/forwarding/lib.sh | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample index df54c9eb5100..e819d049d9ce 100644 --- a/tools/testing/selftests/net/forwarding/forwarding.config.sample +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -14,11 +14,6 @@ NETIFS[p6]=veth5 NETIFS[p7]=veth6 NETIFS[p8]=veth7 -NETIF_TYPE=veth - -# only virtual interfaces (veth) can be created by test infra -#NETIF_CREATE=yes - ############################################################################## # Defines @@ -34,3 +29,7 @@ WAIT_TIME=5 PAUSE_ON_FAIL=no # Whether to pause on cleanup or not. PAUSE_ON_CLEANUP=no +# Type of network interface to create +NETIF_TYPE=veth +# Whether to create virtual interfaces (veth) or not +NETIF_CREATE=yes diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index e989d8a1d4fb..1ac6c62271f3 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -11,6 +11,8 @@ MZ=${MZ:=mausezahn} WAIT_TIME=${WAIT_TIME:=5} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} +NETIF_TYPE=${NETIF_TYPE:=veth} +NETIF_CREATE=${NETIF_CREATE:=yes} if [[ -f forwarding.config ]]; then source forwarding.config -- cgit v1.2.3 From 08486add3a8d22cd3e41cb59028fc397abdcb279 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 12 Mar 2018 16:06:37 -0400 Subject: tc-testing: add TC vlan action tests Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/vlan.json | 410 +++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json new file mode 100644 index 000000000000..4510ddfa6e54 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json @@ -0,0 +1,410 @@ +[ + { + "id": "6f5a", + "name": "Add vlan pop action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "ee6f", + "name": "Add vlan pop action with large index", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 4294967295 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "b6b9", + "name": "Add vlan pop action with jump opcode", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop jump 10 index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*jump 10.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "87c3", + "name": "Add vlan pop action with trap opcode", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop trap index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop trap.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "2b91", + "name": "Add vlan invalid action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan bad_mode", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*bad_mode", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "57fc", + "name": "Add vlan action with invalid protocol type", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push protocol ABCD", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "3989", + "name": "Add vlan push action with default protocol and priority", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 123 index 18", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 18", + "matchPattern": "action order [0-9]+: vlan.*push id 123 protocol 802.1Q priority 0 pipe.*index 18 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "79dc", + "name": "Add vlan push action with protocol 802.1Q and priority 3", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 77 protocol 802.1Q priority 3 continue index 734", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 734", + "matchPattern": "action order [0-9]+: vlan.*push id 77 protocol 802.1Q priority 3 continue.*index 734 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "4d73", + "name": "Add vlan push action with protocol 802.1AD", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 1024 protocol 802.1AD pass index 10000", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 10000", + "matchPattern": "action order [0-9]+: vlan.*push id 1024 protocol 802.1ad priority 0 pass.*index 10000 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "1f7b", + "name": "Add vlan push action with invalid vlan ID", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 5678 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 5678.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "5d02", + "name": "Add vlan push action with invalid IEEE 802.1p priority", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 5 priority 10 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 5.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "6812", + "name": "Add vlan modify action for protocol 802.1Q", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan modify protocol 802.1Q id 5 index 100", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 100", + "matchPattern": "action order [0-9]+: vlan.*modify id 100 protocol 802.1Q priority 0 pipe.*index 100 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "5a31", + "name": "Add vlan modify action for protocol 802.1AD", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan modify protocol 802.1ad id 500 reclassify index 12", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 12", + "matchPattern": "action order [0-9]+: vlan.*modify id 500 protocol 802.1ad priority 0 reclassify.*index 12 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "83a4", + "name": "Delete vlan pop action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan pop index 44" + ], + "cmdUnderTest": "$TC actions del action vlan index 44", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 44 ref", + "matchCount": "0", + "teardown": [] + }, + { + "id": "ed1e", + "name": "Delete vlan push action for protocol 802.1Q", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan push id 4094 protocol 802.1Q index 999" + ], + "cmdUnderTest": "$TC actions del action vlan index 999", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4094 protocol 802.1Q priority 0 pipe.*index 999 ref", + "matchCount": "0", + "teardown": [] + }, + { + "id": "a2a3", + "name": "Flush vlan actions", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan push id 4 protocol 802.1ad index 10", + "$TC actions add action vlan push id 4 protocol 802.1ad index 11", + "$TC actions add action vlan push id 4 protocol 802.1ad index 12", + "$TC actions add action vlan push id 4 protocol 802.1ad index 13" + ], + "cmdUnderTest": "$TC actions flush action vlan", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4 protocol 802.1ad", + "matchCount": "0", + "teardown": [] + }, + { + "id": "1d78", + "name": "Add vlan action with cookie", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 4 cookie a0a0a0a0a0a0a0", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4.*cookie a0a0a0a0a0a0a0", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + } +] -- cgit v1.2.3 From 9ba32046fc2d19697e1a208ce81663239e78e41f Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 12 Mar 2018 16:07:02 -0400 Subject: tc-testing: updated gact tests with batch test cases Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/gact.json | 73 +++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json index e2187b6e0b7a..ae96d0350d7e 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json @@ -465,5 +465,76 @@ "teardown": [ "$TC actions flush action gact" ] + }, + { + "id": "1021", + "name": "Add batch of 32 gact pass actions", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action pass index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action gact" + ] + }, + { + "id": "da7a", + "name": "Add batch of 32 gact continue actions with cookie", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action continue index $i cookie aabbccddeeff112233445566778800a1 \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action gact" + ] + }, + { + "id": "8aa3", + "name": "Delete batch of 32 gact continue actions", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + "for i in `seq 1 32`; do cmd=\"action continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args" + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action gact index $i \"; args=\"$args$cmd\"; done && $TC actions del $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "0", + "teardown": [] } -] +] \ No newline at end of file -- cgit v1.2.3 From 81f77fd0deeb866d65ccc79733df8d2af5217c82 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 14 Mar 2018 10:23:22 -0700 Subject: bpf: add selftest for stackmap with BPF_F_STACK_BUILD_ID test_stacktrace_build_id() is added. It accesses tracepoint urandom_read with "dd" and "urandom_read" and gathers stack traces. Then it reads the stack traces from the stackmap. urandom_read is a statically link binary that reads from /dev/urandom. test_stacktrace_build_id() calls readelf to read build ID of urandom_read and compares it with build ID from the stackmap. Signed-off-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 22 +++ tools/testing/selftests/bpf/Makefile | 12 +- tools/testing/selftests/bpf/test_progs.c | 164 ++++++++++++++++++++- .../selftests/bpf/test_stacktrace_build_id.c | 60 ++++++++ tools/testing/selftests/bpf/urandom_read.c | 22 +++ 5 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/test_stacktrace_build_id.c create mode 100644 tools/testing/selftests/bpf/urandom_read.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index db6bdc375126..1944d0aee7e8 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -231,6 +231,28 @@ enum bpf_attach_type { #define BPF_F_RDONLY (1U << 3) #define BPF_F_WRONLY (1U << 4) +/* Flag for stack_map, store build_id+offset instead of pointer */ +#define BPF_F_STACK_BUILD_ID (1U << 5) + +enum bpf_stack_build_id_status { + /* user space need an empty entry to identify end of a trace */ + BPF_STACK_BUILD_ID_EMPTY = 0, + /* with valid build_id and offset */ + BPF_STACK_BUILD_ID_VALID = 1, + /* couldn't get build_id, fallback to ip */ + BPF_STACK_BUILD_ID_IP = 2, +}; + +#define BPF_BUILD_ID_SIZE 20 +struct bpf_stack_build_id { + __s32 status; + unsigned char build_id[BPF_BUILD_ID_SIZE]; + union { + __u64 offset; + __u64 ip; + }; +}; + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 8567a858b789..b0d29fd5e51c 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -13,6 +13,14 @@ endif CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include LDLIBS += -lcap -lelf -lrt -lpthread +TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read +all: $(TEST_CUSTOM_PROGS) + +$(TEST_CUSTOM_PROGS): urandom_read + +urandom_read: urandom_read.c + $(CC) -o $(TEST_CUSTOM_PROGS) -static $< + # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ test_align test_verifier_log test_dev_cgroup test_tcpbpf_user @@ -21,7 +29,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ - sample_map_ret0.o test_tcpbpf_kern.o + sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -74,3 +82,5 @@ $(OUTPUT)/%.o: %.c $(CLANG) $(CLANG_FLAGS) \ -O2 -target bpf -emit-llvm -c $< -o - | \ $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ + +EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 27ad5404389e..e9df48b306df 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -841,7 +841,8 @@ static void test_tp_attach_query(void) static int compare_map_keys(int map1_fd, int map2_fd) { __u32 key, next_key; - char val_buf[PERF_MAX_STACK_DEPTH * sizeof(__u64)]; + char val_buf[PERF_MAX_STACK_DEPTH * + sizeof(struct bpf_stack_build_id)]; int err; err = bpf_map_get_next_key(map1_fd, NULL, &key); @@ -964,6 +965,166 @@ out: return; } +static int extract_build_id(char *build_id, size_t size) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + + fp = popen("readelf -n ./urandom_read | grep 'Build ID'", "r"); + if (fp == NULL) + return -1; + + if (getline(&line, &len, fp) == -1) + goto err; + fclose(fp); + + if (len > size) + len = size; + memcpy(build_id, line, len); + build_id[len] = '\0'; + return 0; +err: + fclose(fp); + return -1; +} + +static void test_stacktrace_build_id(void) +{ + int control_map_fd, stackid_hmap_fd, stackmap_fd; + const char *file = "./test_stacktrace_build_id.o"; + int bytes, efd, err, pmu_fd, prog_fd; + struct perf_event_attr attr = {}; + __u32 key, previous_key, val, duration = 0; + struct bpf_object *obj; + char buf[256]; + int i, j; + struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; + int build_id_matches = 0; + + err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); + if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) + goto out; + + /* Get the ID for the sched/sched_switch tracepoint */ + snprintf(buf, sizeof(buf), + "/sys/kernel/debug/tracing/events/random/urandom_read/id"); + efd = open(buf, O_RDONLY, 0); + if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno)) + goto close_prog; + + bytes = read(efd, buf, sizeof(buf)); + close(efd); + if (CHECK(bytes <= 0 || bytes >= sizeof(buf), + "read", "bytes %d errno %d\n", bytes, errno)) + goto close_prog; + + /* Open the perf event and attach bpf progrram */ + attr.config = strtol(buf, NULL, 0); + attr.type = PERF_TYPE_TRACEPOINT; + attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN; + attr.sample_period = 1; + attr.wakeup_events = 1; + pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, + 0 /* cpu 0 */, -1 /* group id */, + 0 /* flags */); + if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n", + pmu_fd, errno)) + goto close_prog; + + err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); + if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", + err, errno)) + goto close_pmu; + + err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); + if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", + err, errno)) + goto disable_pmu; + + /* find map fds */ + control_map_fd = bpf_find_map(__func__, obj, "control_map"); + if (CHECK(control_map_fd < 0, "bpf_find_map control_map", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); + if (CHECK(stackid_hmap_fd < 0, "bpf_find_map stackid_hmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); + if (CHECK(stackmap_fd < 0, "bpf_find_map stackmap", "err %d errno %d\n", + err, errno)) + goto disable_pmu; + + assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null") + == 0); + assert(system("./urandom_read if=/dev/urandom of=/dev/zero count=4 2> /dev/null") == 0); + /* disable stack trace collection */ + key = 0; + val = 1; + bpf_map_update_elem(control_map_fd, &key, &val, 0); + + /* for every element in stackid_hmap, we can find a corresponding one + * in stackmap, and vise versa. + */ + err = compare_map_keys(stackid_hmap_fd, stackmap_fd); + if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = compare_map_keys(stackmap_fd, stackid_hmap_fd); + if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = extract_build_id(buf, 256); + + if (CHECK(err, "get build_id with readelf", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = bpf_map_get_next_key(stackmap_fd, NULL, &key); + if (CHECK(err, "get_next_key from stackmap", + "err %d, errno %d\n", err, errno)) + goto disable_pmu; + + do { + char build_id[64]; + + err = bpf_map_lookup_elem(stackmap_fd, &key, id_offs); + if (CHECK(err, "lookup_elem from stackmap", + "err %d, errno %d\n", err, errno)) + goto disable_pmu; + for (i = 0; i < PERF_MAX_STACK_DEPTH; ++i) + if (id_offs[i].status == BPF_STACK_BUILD_ID_VALID && + id_offs[i].offset != 0) { + for (j = 0; j < 20; ++j) + sprintf(build_id + 2 * j, "%02x", + id_offs[i].build_id[j] & 0xff); + if (strstr(buf, build_id) != NULL) + build_id_matches = 1; + } + previous_key = key; + } while (bpf_map_get_next_key(stackmap_fd, &previous_key, &key) == 0); + + CHECK(build_id_matches < 1, "build id match", + "Didn't find expected build ID from the map"); + +disable_pmu: + ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); + +close_pmu: + close(pmu_fd); + +close_prog: + bpf_object__close(obj); + +out: + return; +} + int main(void) { test_pkt_access(); @@ -976,6 +1137,7 @@ int main(void) test_obj_name(); test_tp_attach_query(); test_stacktrace_map(); + test_stacktrace_build_id(); printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/tools/testing/selftests/bpf/test_stacktrace_build_id.c b/tools/testing/selftests/bpf/test_stacktrace_build_id.c new file mode 100644 index 000000000000..b755bd783ce5 --- /dev/null +++ b/tools/testing/selftests/bpf/test_stacktrace_build_id.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include "bpf_helpers.h" + +#ifndef PERF_MAX_STACK_DEPTH +#define PERF_MAX_STACK_DEPTH 127 +#endif + +struct bpf_map_def SEC("maps") control_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") stackid_hmap = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 10000, +}; + +struct bpf_map_def SEC("maps") stackmap = { + .type = BPF_MAP_TYPE_STACK_TRACE, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_stack_build_id) + * PERF_MAX_STACK_DEPTH, + .max_entries = 128, + .map_flags = BPF_F_STACK_BUILD_ID, +}; + +/* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */ +struct random_urandom_args { + unsigned long long pad; + int got_bits; + int pool_left; + int input_left; +}; + +SEC("tracepoint/random/urandom_read") +int oncpu(struct random_urandom_args *args) +{ + __u32 key = 0, val = 0, *value_p; + + value_p = bpf_map_lookup_elem(&control_map, &key); + if (value_p && *value_p) + return 0; /* skip if non-zero *value_p */ + + /* The size of stackmap and stackid_hmap should be the same */ + key = bpf_get_stackid(args, &stackmap, BPF_F_USER_STACK); + if ((int)key >= 0) + bpf_map_update_elem(&stackid_hmap, &key, &val, 0); + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/urandom_read.c b/tools/testing/selftests/bpf/urandom_read.c new file mode 100644 index 000000000000..4acfdebf36fa --- /dev/null +++ b/tools/testing/selftests/bpf/urandom_read.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 256 +int main(void) +{ + int fd = open("/dev/urandom", O_RDONLY); + int i; + char buf[BUF_SIZE]; + + if (fd < 0) + return 1; + for (i = 0; i < 4; ++i) + read(fd, buf, BUF_SIZE); + + close(fd); + return 0; +} -- cgit v1.2.3 From 171a48717beeacb66be85c1e8e401111d3a0262c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:39 -0700 Subject: selftests: fib_tests: Use an alias for ip command Replace 'ip -netns testns' with the alias IP. Shortens the line lengths and makes running the commands manually a bit easier. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 169 ++++++++++++++++--------------- 1 file changed, 85 insertions(+), 84 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index b617985ecdc1..953254439e39 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -7,6 +7,7 @@ ret=0 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} +IP="ip -netns testns" log_test() { @@ -32,19 +33,19 @@ setup() { set -e ip netns add testns - ip -netns testns link set dev lo up + $IP link set dev lo up - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + $IP link add dummy0 type dummy + $IP link set dev dummy0 up + $IP address add 198.51.100.1/24 dev dummy0 + $IP -6 address add 2001:db8:1::1/64 dev dummy0 set +e } cleanup() { - ip -netns testns link del dev dummy0 &> /dev/null + $IP link del dev dummy0 &> /dev/null ip netns del testns } @@ -56,19 +57,19 @@ fib_unreg_unicast_test() setup echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link del dev dummy0 + $IP link del dev dummy0 set +e echo " Nexthop device deleted" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 2 "IPv4 fibmatch - no route" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch - no route" cleanup @@ -83,43 +84,43 @@ fib_unreg_multipath_test() setup set -e - ip -netns testns link add dummy1 type dummy - ip -netns testns link set dev dummy1 up - ip -netns testns address add 192.0.2.1/24 dev dummy1 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 + $IP link add dummy1 type dummy + $IP link set dev dummy1 up + $IP address add 192.0.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 - ip -netns testns route add 203.0.113.0/24 \ + $IP route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip -netns testns -6 route add 2001:db8:3::/64 \ + $IP -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 set +e echo " Start point" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link del dev dummy0 + $IP link del dev dummy0 set +e echo " One nexthop device deleted" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 2 "IPv4 - multipath route removed on delete" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. log_test $? 0 "IPv6 - multipath down to single path" set -e - ip -netns testns link del dev dummy1 + $IP link del dev dummy1 set +e echo " Second nexthop device deleted" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 - no route" cleanup @@ -139,19 +140,19 @@ fib_down_unicast_test() setup echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " Route deleted on down" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 2 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch" cleanup @@ -162,31 +163,31 @@ fib_down_multipath_test_do() local down_dev=$1 local up_dev=$2 - ip -netns testns route get fibmatch 203.0.113.1 \ + $IP route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null log_test $? 2 "IPv4 fibmatch on down device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ + $IP -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null log_test $? 2 "IPv6 fibmatch on down device" - ip -netns testns route get fibmatch 203.0.113.1 \ + $IP route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null log_test $? 0 "IPv4 fibmatch on up device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ + $IP -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null log_test $? 0 "IPv6 fibmatch on up device" - ip -netns testns route get fibmatch 203.0.113.1 | \ + $IP route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" log_test $? 0 "IPv4 flags on down device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ + $IP -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" log_test $? 0 "IPv6 flags on down device" - ip -netns testns route get fibmatch 203.0.113.1 | \ + $IP route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" log_test $? 1 "IPv4 flags on up device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ + $IP -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" log_test $? 1 "IPv6 flags on up device" } @@ -199,53 +200,53 @@ fib_down_multipath_test() setup set -e - ip -netns testns link add dummy1 type dummy - ip -netns testns link set dev dummy1 up + $IP link add dummy1 type dummy + $IP link set dev dummy1 up - ip -netns testns address add 192.0.2.1/24 dev dummy1 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 + $IP address add 192.0.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 - ip -netns testns route add 203.0.113.0/24 \ + $IP route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip -netns testns -6 route add 2001:db8:3::/64 \ + $IP -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 set +e echo " Verify start point" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " One device down, one up" fib_down_multipath_test_do "dummy0" "dummy1" set -e - ip -netns testns link set dev dummy0 up - ip -netns testns link set dev dummy1 down + $IP link set dev dummy0 up + $IP link set dev dummy1 down set +e echo " Other device down and up" fib_down_multipath_test_do "dummy1" "dummy0" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " Both devices down" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 2 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 fibmatch" - ip -netns testns link del dev dummy1 + $IP link del dev dummy1 cleanup } @@ -264,55 +265,55 @@ fib_carrier_local_test() setup set -e - ip -netns testns link set dev dummy0 carrier on + $IP link set dev dummy0 carrier on set +e echo " Start point" - ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null + $IP route get fibmatch 198.51.100.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.1 | \ + $IP route get fibmatch 198.51.100.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 - no linkdown flag" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ + $IP -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 - no linkdown flag" set -e - ip -netns testns link set dev dummy0 carrier off + $IP link set dev dummy0 carrier off sleep 1 set +e echo " Carrier off on nexthop" - ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null + $IP route get fibmatch 198.51.100.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.1 | \ + $IP route get fibmatch 198.51.100.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 - linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ + $IP -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 - linkdown flag set" set -e - ip -netns testns address add 192.0.2.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + $IP address add 192.0.2.1/24 dev dummy0 + $IP -6 address add 2001:db8:2::1/64 dev dummy0 set +e echo " Route to local address with carrier down" - ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null + $IP route get fibmatch 192.0.2.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 192.0.2.1 | \ + $IP route get fibmatch 192.0.2.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ + $IP -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 linkdown flag set" @@ -329,54 +330,54 @@ fib_carrier_unicast_test() setup set -e - ip -netns testns link set dev dummy0 carrier on + $IP link set dev dummy0 carrier on set +e echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.2 | \ + $IP route get fibmatch 198.51.100.2 | \ grep -q "linkdown" log_test $? 1 "IPv4 no linkdown flag" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ + $IP -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" log_test $? 1 "IPv6 no linkdown flag" set -e - ip -netns testns link set dev dummy0 carrier off + $IP link set dev dummy0 carrier off set +e echo " Carrier down" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.2 | \ + $IP route get fibmatch 198.51.100.2 | \ grep -q "linkdown" log_test $? 0 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ + $IP -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" set -e - ip -netns testns address add 192.0.2.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + $IP address add 192.0.2.1/24 dev dummy0 + $IP -6 address add 2001:db8:2::1/64 dev dummy0 set +e echo " Second address added with carrier down" - ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null + $IP route get fibmatch 192.0.2.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 192.0.2.2 | \ + $IP route get fibmatch 192.0.2.2 | \ grep -q "linkdown" log_test $? 0 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ + $IP -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" -- cgit v1.2.3 From a511858c7536fab15a59a0a2aee14c5a909da23a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:40 -0700 Subject: selftests: fib_tests: Allow user to run a specific test Allow a user to run just a specific fib test by setting the TEST environment variable. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 953254439e39..cfdeb35bfed5 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -392,9 +392,13 @@ fib_carrier_test() fib_test() { - fib_unreg_test - fib_down_test - fib_carrier_test + if [ -n "$TEST" ]; then + eval $TEST + else + fib_unreg_test + fib_down_test + fib_carrier_test + fi } if [ "$(id -u)" -ne 0 ];then -- cgit v1.2.3 From 654d3a7821e838dd7608d88922d8d3db9bdb95b4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:41 -0700 Subject: selftests: fib_tests: Add IPv6 nexthop spec tests Add series of tests for valid and invalid nexthop specs for IPv6. $ TEST=fib_nexthop_test ./fib_tests.sh ... IPv6 nexthop tests TEST: Directly connected nexthop, unicast address [ OK ] TEST: Directly connected nexthop, unicast address with device [ OK ] TEST: Gateway is linklocal address [ OK ] TEST: Gateway is linklocal address, no device [ OK ] TEST: Gateway can not be local unicast address [ OK ] TEST: Gateway can not be local unicast address, with device [ OK ] TEST: Gateway can not be a local linklocal address [ OK ] TEST: Gateway can be local address in a VRF [ OK ] TEST: Gateway can be local address in a VRF, with device [ OK ] TEST: Gateway can be local linklocal address in a VRF [ OK ] TEST: Redirect to VRF lookup [ OK ] TEST: VRF route, gateway can be local address in default VRF [ OK ] TEST: VRF route, gateway can not be a local address [ OK ] TEST: VRF route, gateway can not be a local addr with device [ OK ] Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 180 ++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index cfdeb35bfed5..9164e60d4b66 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -6,6 +6,7 @@ ret=0 +VERBOSE=${VERBOSE:=0} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} IP="ip -netns testns" @@ -16,10 +17,10 @@ log_test() local msg="$3" if [ ${rc} -eq ${expected} ]; then - printf " %-60s [ OK ]\n" "${msg}" + printf " TEST: %-60s [ OK ]\n" "${msg}" else ret=1 - printf " %-60s [FAIL]\n" "${msg}" + printf " TEST: %-60s [FAIL]\n" "${msg}" if [ "${PAUSE_ON_FAIL}" = "yes" ]; then echo echo "hit enter to continue, 'q' to quit" @@ -49,6 +50,28 @@ cleanup() ip netns del testns } +get_linklocal() +{ + local dev=$1 + local addr + + addr=$($IP -6 -br addr show dev ${dev} | \ + awk '{ + for (i = 3; i <= NF; ++i) { + if ($i ~ /^fe80/) + print $i + } + }' + ) + addr=${addr/\/*} + + [ -z "$addr" ] && return 1 + + echo $addr + + return 0 +} + fib_unreg_unicast_test() { echo @@ -390,6 +413,158 @@ fib_carrier_test() fib_carrier_unicast_test } +################################################################################ +# Tests on nexthop spec + +# run 'ip route add' with given spec +add_rt() +{ + local desc="$1" + local erc=$2 + local vrf=$3 + local pfx=$4 + local gw=$5 + local dev=$6 + local cmd out rc + + [ "$vrf" = "-" ] && vrf="default" + [ -n "$gw" ] && gw="via $gw" + [ -n "$dev" ] && dev="dev $dev" + + cmd="$IP route add vrf $vrf $pfx $gw $dev" + if [ "$VERBOSE" = "1" ]; then + printf "\n COMMAND: $cmd\n" + fi + + out=$(eval $cmd 2>&1) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + log_test $rc $erc "$desc" +} + +fib4_nexthop() +{ + echo + echo "IPv4 nexthop tests" + + echo "<<< write me >>>" +} + +fib6_nexthop() +{ + local lldummy=$(get_linklocal dummy0) + local llv1=$(get_linklocal dummy0) + + if [ -z "$lldummy" ]; then + echo "Failed to get linklocal address for dummy0" + return 1 + fi + if [ -z "$llv1" ]; then + echo "Failed to get linklocal address for veth1" + return 1 + fi + + echo + echo "IPv6 nexthop tests" + + add_rt "Directly connected nexthop, unicast address" 0 \ + - 2001:db8:101::/64 2001:db8:1::2 + add_rt "Directly connected nexthop, unicast address with device" 0 \ + - 2001:db8:102::/64 2001:db8:1::2 "dummy0" + add_rt "Gateway is linklocal address" 0 \ + - 2001:db8:103::1/64 $llv1 "veth0" + + # fails because LL address requires a device + add_rt "Gateway is linklocal address, no device" 2 \ + - 2001:db8:104::1/64 $llv1 + + # local address can not be a gateway + add_rt "Gateway can not be local unicast address" 2 \ + - 2001:db8:105::/64 2001:db8:1::1 + add_rt "Gateway can not be local unicast address, with device" 2 \ + - 2001:db8:106::/64 2001:db8:1::1 "dummy0" + add_rt "Gateway can not be a local linklocal address" 2 \ + - 2001:db8:107::1/64 $lldummy "dummy0" + + # VRF tests + add_rt "Gateway can be local address in a VRF" 0 \ + - 2001:db8:108::/64 2001:db8:51::2 + add_rt "Gateway can be local address in a VRF, with device" 0 \ + - 2001:db8:109::/64 2001:db8:51::2 "veth0" + add_rt "Gateway can be local linklocal address in a VRF" 0 \ + - 2001:db8:110::1/64 $llv1 "veth0" + + add_rt "Redirect to VRF lookup" 0 \ + - 2001:db8:111::/64 "" "red" + + add_rt "VRF route, gateway can be local address in default VRF" 0 \ + red 2001:db8:112::/64 2001:db8:51::1 + + # local address in same VRF fails + add_rt "VRF route, gateway can not be a local address" 2 \ + red 2001:db8:113::1/64 2001:db8:2::1 + add_rt "VRF route, gateway can not be a local addr with device" 2 \ + red 2001:db8:114::1/64 2001:db8:2::1 "dummy1" +} + +# Default VRF: +# dummy0 - 198.51.100.1/24 2001:db8:1::1/64 +# veth0 - 192.0.2.1/24 2001:db8:51::1/64 +# +# VRF red: +# dummy1 - 192.168.2.1/24 2001:db8:2::1/64 +# veth1 - 192.0.2.2/24 2001:db8:51::2/64 +# +# [ dummy0 veth0 ]--[ veth1 dummy1 ] + +fib_nexthop_test() +{ + setup + + set -e + + $IP -4 rule add pref 32765 table local + $IP -4 rule del pref 0 + $IP -6 rule add pref 32765 table local + $IP -6 rule del pref 0 + + $IP link add red type vrf table 1 + $IP link set red up + $IP -4 route add vrf red unreachable default metric 4278198272 + $IP -6 route add vrf red unreachable default metric 4278198272 + + $IP link add veth0 type veth peer name veth1 + $IP link set dev veth0 up + $IP address add 192.0.2.1/24 dev veth0 + $IP -6 address add 2001:db8:51::1/64 dev veth0 + + $IP link set dev veth1 vrf red up + $IP address add 192.0.2.2/24 dev veth1 + $IP -6 address add 2001:db8:51::2/64 dev veth1 + + $IP link add dummy1 type dummy + $IP link set dev dummy1 vrf red up + $IP address add 192.168.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 + set +e + + sleep 1 + fib4_nexthop + fib6_nexthop + + ( + $IP link del dev dummy1 + $IP link del veth0 + $IP link del red + ) 2>/dev/null + cleanup +} + +################################################################################ +# + fib_test() { if [ -n "$TEST" ]; then @@ -398,6 +573,7 @@ fib_test() fib_unreg_test fib_down_test fib_carrier_test + fib_nexthop_test fi } -- cgit v1.2.3 From 5dce837944de76b5ba9cff6d2a3ecde6f4838665 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 16 Mar 2018 10:41:14 -0700 Subject: selftests/txtimestamp: Add more configurable parameters Add a way to configure if poll() should wait forever for an event, the number of packets that should be sent for each and if there should be any delay between packets. Signed-off-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- .../selftests/networking/timestamping/txtimestamp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c index 5df07047ca86..81a98a240456 100644 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.c +++ b/tools/testing/selftests/networking/timestamping/txtimestamp.c @@ -68,9 +68,11 @@ static int cfg_num_pkts = 4; static int do_ipv4 = 1; static int do_ipv6 = 1; static int cfg_payload_len = 10; +static int cfg_poll_timeout = 100; static bool cfg_show_payload; static bool cfg_do_pktinfo; static bool cfg_loop_nodata; +static bool cfg_no_delay; static uint16_t dest_port = 9000; static struct sockaddr_in daddr; @@ -171,7 +173,7 @@ static void __poll(int fd) memset(&pollfd, 0, sizeof(pollfd)); pollfd.fd = fd; - ret = poll(&pollfd, 1, 100); + ret = poll(&pollfd, 1, cfg_poll_timeout); if (ret != 1) error(1, errno, "poll"); } @@ -371,7 +373,8 @@ static void do_test(int family, unsigned int opt) error(1, errno, "send"); /* wait for all errors to be queued, else ACKs arrive OOO */ - usleep(50 * 1000); + if (!cfg_no_delay) + usleep(50 * 1000); __poll(fd); @@ -392,6 +395,9 @@ static void __attribute__((noreturn)) usage(const char *filepath) " -4: only IPv4\n" " -6: only IPv6\n" " -h: show this message\n" + " -c N: number of packets for each test\n" + " -D: no delay between packets\n" + " -F: poll() waits forever for an event\n" " -I: request PKTINFO\n" " -l N: send N bytes at a time\n" " -n: set no-payload option\n" @@ -409,7 +415,7 @@ static void parse_opt(int argc, char **argv) int proto_count = 0; char c; - while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) { + while ((c = getopt(argc, argv, "46c:DFhIl:np:rRux")) != -1) { switch (c) { case '4': do_ipv6 = 0; @@ -417,6 +423,15 @@ static void parse_opt(int argc, char **argv) case '6': do_ipv4 = 0; break; + case 'c': + cfg_num_pkts = strtoul(optarg, NULL, 10); + break; + case 'D': + cfg_no_delay = true; + break; + case 'F': + cfg_poll_timeout = -1; + break; case 'I': cfg_do_pktinfo = true; break; -- cgit v1.2.3 From 380e29a6b71fac7ce7a437ab2f7e305c3de8076f Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:38 +0100 Subject: selftests: pmtu: Reverse return codes of functions David suggests it's more intuitive to return non-zero on failures, and zero on success. No need to introduce tail 'return 0' in functions, they will return the exit code of the last command anyway. Suggested-by: David Ahern Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 6c19c148cef8..65842a2afa55 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -26,14 +26,12 @@ vti6_b_addr="fd00:2::b" vti6_mask="64" setup_namespaces() { - ip netns add ${NS_A} || return 0 + ip netns add ${NS_A} || return 1 ip netns add ${NS_B} - - return 1 } setup_veth() { - ${ns_a} ip link add veth_a type veth peer name veth_b || return 0 + ${ns_a} ip link add veth_a type veth peer name veth_b || return 1 ${ns_a} ip link set veth_b netns ${NS_B} ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a @@ -41,12 +39,10 @@ setup_veth() { ${ns_a} ip link set veth_a up ${ns_b} ip link set veth_b up - - return 1 } setup_vti6() { - ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 0 + ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 1 ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a @@ -56,12 +52,10 @@ setup_vti6() { ${ns_b} ip link set vti_b up sleep 1 - - return 1 } setup_xfrm() { - ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 0 + ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel @@ -70,8 +64,6 @@ setup_xfrm() { ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel - - return 1 } setup() { @@ -79,13 +71,13 @@ setup() { [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 - setup_namespaces && echo "SKIP: namespaces not supported" && exit 0 - setup_veth && echo "SKIP: veth not supported" && exit 0 + setup_namespaces || { echo "SKIP: namespaces not supported"; exit 0; } + setup_veth || { echo "SKIP: veth not supported"; exit 0; } case ${tunnel_type} in "vti6") - setup_vti6 && echo "SKIP: vti6 not supported" && exit 0 - setup_xfrm && echo "SKIP: xfrm not supported" && exit 0 + setup_vti6 || { echo "SKIP: vti6 not supported"; exit 0; } + setup_xfrm || { echo "SKIP: xfrm not supported"; exit 0; } ;; *) ;; -- cgit v1.2.3 From 822d2f86c485113dc5df7648e97aaef3607c4479 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:39 +0100 Subject: selftests: pmtu: Use namespace command prefix to fetch route mtu In 7af137b72131 ("selftests: net: Introduce first PMTU test") I accidentally assumed route_get_* helpers would run from a single namespace. Make them a bit more generic, by passing the namespace command prefix as a parameter instead. Fixes: 7af137b72131 ("selftests: net: Introduce first PMTU test") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 65842a2afa55..0d010f982272 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -98,15 +98,17 @@ mtu() { } route_get_dst_exception() { - dst="${1}" + ns_cmd="${1}" + dst="${2}" - ${ns_a} ip route get "${dst}" + ${ns_cmd} ip route get "${dst}" } route_get_dst_pmtu_from_exception() { - dst="${1}" + ns_cmd="${1}" + dst="${2}" - exception="$(route_get_dst_exception ${dst})" + exception="$(route_get_dst_exception "${ns_cmd}" ${dst})" next=0 for i in ${exception}; do [ ${next} -eq 1 ] && echo "${i}" && return @@ -125,7 +127,7 @@ test_pmtu_vti6_exception() { ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null # Check that exception was created - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" = "" ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" exit 1 fi @@ -133,14 +135,14 @@ test_pmtu_vti6_exception() { # Decrease tunnel MTU, check for PMTU decrease in route exception mtu "${ns_a}" vti_a 3000 - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 3000 ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" exit 1 fi # Increase tunnel MTU, check for PMTU increase in route exception mtu "${ns_a}" vti_a 9000 - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 9000 ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" exit 1 fi -- cgit v1.2.3 From f2c929feeccd3d56be284b9e24e04cd3c4779a4f Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:40 +0100 Subject: selftests: pmtu: Factor out MTU parsing helper ...so that it can be used for any iproute command output. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 0d010f982272..2d33e533ad36 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -97,6 +97,16 @@ mtu() { ${ns_cmd} ip link set dev ${dev} mtu ${mtu} } +mtu_parse() { + input="${1}" + + next=0 + for i in ${input}; do + [ ${next} -eq 1 ] && echo "${i}" && return + [ "${i}" = "mtu" ] && next=1 + done +} + route_get_dst_exception() { ns_cmd="${1}" dst="${2}" @@ -108,12 +118,7 @@ route_get_dst_pmtu_from_exception() { ns_cmd="${1}" dst="${2}" - exception="$(route_get_dst_exception "${ns_cmd}" ${dst})" - next=0 - for i in ${exception}; do - [ ${next} -eq 1 ] && echo "${i}" && return - [ "${i}" = "mtu" ] && next=1 - done + mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" } test_pmtu_vti6_exception() { -- cgit v1.2.3 From 36455bd1e977ef1ccd8e89018bd14d0a5b96b4e5 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:41 +0100 Subject: selftests: pmtu: Introduce support for multiple tests Introduce list of tests and their descriptions, and loop on it in main body. Tests will now just take care of calling setup with a list of "units" they need, and return 0 on success, 1 on failure, 2 if the test had to be skipped. Main script body will take care of displaying results and cleaning up after every test. Introduce guard variable so that we don't clean up twice in case of interrupts or unexpected failures. The pmtu_vti6_exception test can now run its third step even if the previous one failed, as we can return values from it. Also introduce support to display test descriptions, and display aligned OK/FAIL/SKIP test outcomes. Buffer error strings so that in case of failure we can display them right under the outcome for each test. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 87 ++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 26 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 2d33e533ad36..733de6053b5c 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -5,13 +5,16 @@ # # Tests currently implemented: # -# - test_pmtu_vti6_exception +# - pmtu_vti6_exception # Set up vti6 tunnel on top of veth, with xfrm states and policies, in two # namespaces with matching endpoints. Check that route exception is # created by exceeding link layer MTU with ping to other endpoint. Then # decrease and increase MTU of tunnel, checking that route exception PMTU # changes accordingly +tests=" + pmtu_vti6_exception vti6: PMTU exceptions" + NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" ns_a="ip netns exec ${NS_A}" @@ -25,6 +28,19 @@ vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" +cleanup_done=1 +err_buf= + +err() { + err_buf="${err_buf}${1} +" +} + +err_flush() { + echo -n "${err_buf}" + err_buf= +} + setup_namespaces() { ip netns add ${NS_A} || return 1 ip netns add ${NS_B} @@ -67,26 +83,19 @@ setup_xfrm() { } setup() { - tunnel_type="$1" - - [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 - - setup_namespaces || { echo "SKIP: namespaces not supported"; exit 0; } - setup_veth || { echo "SKIP: veth not supported"; exit 0; } + [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return 1 - case ${tunnel_type} in - "vti6") - setup_vti6 || { echo "SKIP: vti6 not supported"; exit 0; } - setup_xfrm || { echo "SKIP: xfrm not supported"; exit 0; } - ;; - *) - ;; - esac + cleanup_done=0 + for arg do + eval setup_${arg} || { echo " ${arg} not supported"; return 1; } + done } cleanup() { + [ ${cleanup_done} -eq 1 ] && return ip netns del ${NS_A} 2 > /dev/null ip netns del ${NS_B} 2 > /dev/null + cleanup_done=1 } mtu() { @@ -122,7 +131,8 @@ route_get_dst_pmtu_from_exception() { } test_pmtu_vti6_exception() { - setup vti6 + setup namespaces veth vti6 xfrm || return 2 + fail=0 # Create route exception by exceeding link layer MTU mtu "${ns_a}" veth_a 4000 @@ -133,30 +143,55 @@ test_pmtu_vti6_exception() { # Check that exception was created if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then - echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" - exit 1 + err " tunnel exceeding link layer MTU didn't create route exception" + return 1 fi # Decrease tunnel MTU, check for PMTU decrease in route exception mtu "${ns_a}" vti_a 3000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then - echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" - exit 1 + err " decreasing tunnel MTU didn't decrease route exception PMTU" + fail=1 fi # Increase tunnel MTU, check for PMTU increase in route exception mtu "${ns_a}" vti_a 9000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then - echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" - exit 1 + err " increasing tunnel MTU didn't increase route exception PMTU" + fail=1 fi - echo "PASS" + return ${fail} } trap cleanup EXIT -test_pmtu_vti6_exception - -exit 0 +exitcode=0 +desc=0 +IFS=" +" +for t in ${tests}; do + [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 + + ( + unset IFS + eval test_${name} + ret=$? + cleanup + + if [ $ret -eq 0 ]; then + printf "TEST: %-60s [ OK ]\n" "${t}" + elif [ $ret -eq 1 ]; then + printf "TEST: %-60s [FAIL]\n" "${t}" + err_flush + exit 1 + elif [ $ret -eq 2 ]; then + printf "TEST: %-60s [SKIP]\n" "${t}" + err_flush + fi + ) + [ $? -ne 0 ] && exitcode=1 +done + +exit ${exitcode} -- cgit v1.2.3 From a41c789bdcc1e3d8fe0d82ee80c22aa4f4508004 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:42 +0100 Subject: selftests: pmtu: Add pmtu_vti4_default_mtu test This test checks that the MTU assigned by default to a vti (IPv4) interface created on top of veth is simply veth's MTU minus the length of the encapsulated IPv4 header. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 86 +++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 13 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 733de6053b5c..be13b3232c12 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -1,7 +1,8 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # -# Check that route PMTU values match expectations +# Check that route PMTU values match expectations, and that initial device MTU +# values are assigned correctly # # Tests currently implemented: # @@ -11,19 +12,32 @@ # created by exceeding link layer MTU with ping to other endpoint. Then # decrease and increase MTU of tunnel, checking that route exception PMTU # changes accordingly +# +# - pmtu_vti4_default_mtu +# Set up vti4 tunnel on top of veth, in two namespaces with matching +# endpoints. Check that MTU assigned to vti interface is the MTU of the +# lower layer (veth) minus additional lower layer headers (zero, for veth) +# minus IPv4 header length tests=" - pmtu_vti6_exception vti6: PMTU exceptions" + pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_default_mtu vti4: default MTU assignment" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" ns_a="ip netns exec ${NS_A}" ns_b="ip netns exec ${NS_B}" +veth4_a_addr="192.168.1.1" +veth4_b_addr="192.168.1.2" +veth4_mask="24" veth6_a_addr="fd00:1::a" veth6_b_addr="fd00:1::b" veth6_mask="64" +vti4_a_addr="192.168.2.1" +vti4_b_addr="192.168.2.2" +vti4_mask="24" vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" @@ -50,6 +64,9 @@ setup_veth() { ${ns_a} ip link add veth_a type veth peer name veth_b || return 1 ${ns_a} ip link set veth_b netns ${NS_B} + ${ns_a} ip addr add ${veth4_a_addr}/${veth4_mask} dev veth_a + ${ns_b} ip addr add ${veth4_b_addr}/${veth4_mask} dev veth_b + ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a ${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b @@ -57,19 +74,36 @@ setup_veth() { ${ns_b} ip link set veth_b up } -setup_vti6() { - ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 1 - ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 +setup_vti() { + proto=${1} + veth_a_addr="${2}" + veth_b_addr="${3}" + vti_a_addr="${4}" + vti_b_addr="${5}" + vti_mask=${6} - ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a - ${ns_b} ip addr add ${vti6_b_addr}/${vti6_mask} dev vti_b + [ ${proto} -eq 6 ] && vti_type="vti6" || vti_type="vti" - ${ns_a} ip link set vti_a up - ${ns_b} ip link set vti_b up + ${ns_a} ip link add vti${proto}_a type ${vti_type} local ${veth_a_addr} remote ${veth_b_addr} key 10 || return 1 + ${ns_b} ip link add vti${proto}_b type ${vti_type} local ${veth_b_addr} remote ${veth_a_addr} key 10 + + ${ns_a} ip addr add ${vti_a_addr}/${vti_mask} dev vti${proto}_a + ${ns_b} ip addr add ${vti_b_addr}/${vti_mask} dev vti${proto}_b + + ${ns_a} ip link set vti${proto}_a up + ${ns_b} ip link set vti${proto}_b up sleep 1 } +setup_vti4() { + setup_vti 4 ${veth4_a_addr} ${veth4_b_addr} ${vti4_a_addr} ${vti4_b_addr} ${vti4_mask} +} + +setup_vti6() { + setup_vti 6 ${veth6_a_addr} ${veth6_b_addr} ${vti6_a_addr} ${vti6_b_addr} ${vti6_mask} +} + setup_xfrm() { ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel @@ -116,6 +150,20 @@ mtu_parse() { done } +link_get() { + ns_cmd="${1}" + name="${2}" + + ${ns_cmd} ip link show dev "${name}" +} + +link_get_mtu() { + ns_cmd="${1}" + name="${2}" + + mtu_parse "$(link_get "${ns_cmd}" ${name})" +} + route_get_dst_exception() { ns_cmd="${1}" dst="${2}" @@ -137,8 +185,8 @@ test_pmtu_vti6_exception() { # Create route exception by exceeding link layer MTU mtu "${ns_a}" veth_a 4000 mtu "${ns_b}" veth_b 4000 - mtu "${ns_a}" vti_a 5000 - mtu "${ns_b}" vti_b 5000 + mtu "${ns_a}" vti6_a 5000 + mtu "${ns_b}" vti6_b 5000 ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null # Check that exception was created @@ -148,7 +196,7 @@ test_pmtu_vti6_exception() { fi # Decrease tunnel MTU, check for PMTU decrease in route exception - mtu "${ns_a}" vti_a 3000 + mtu "${ns_a}" vti6_a 3000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then err " decreasing tunnel MTU didn't decrease route exception PMTU" @@ -156,7 +204,7 @@ test_pmtu_vti6_exception() { fi # Increase tunnel MTU, check for PMTU increase in route exception - mtu "${ns_a}" vti_a 9000 + mtu "${ns_a}" vti6_a 9000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then err " increasing tunnel MTU didn't increase route exception PMTU" fail=1 @@ -165,6 +213,18 @@ test_pmtu_vti6_exception() { return ${fail} } +test_pmtu_vti4_default_mtu() { + setup namespaces veth vti4 || return 2 + + # Check that MTU of vti device is MTU of veth minus IPv4 header length + veth_mtu="$(link_get_mtu "${ns_a}" veth_a)" + vti4_mtu="$(link_get_mtu "${ns_a}" vti4_a)" + if [ $((veth_mtu - vti4_mtu)) -ne 20 ]; then + err " vti MTU ${vti4_mtu} is not veth MTU ${veth_mtu} minus IPv4 header length" + return 1 + fi +} + trap cleanup EXIT exitcode=0 -- cgit v1.2.3 From 35b49424b8a49edb6de6e7ec54bd8edb568031c2 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:43 +0100 Subject: selftests: pmtu: Add pmtu_vti6_default_mtu test Same as pmtu_vti4_default_mtu, but on IPv6 with vti6. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index be13b3232c12..5d9af22b360a 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -18,10 +18,14 @@ # endpoints. Check that MTU assigned to vti interface is the MTU of the # lower layer (veth) minus additional lower layer headers (zero, for veth) # minus IPv4 header length +# +# - pmtu_vti6_default_mtu +# Same as above, for IPv6 tests=" pmtu_vti6_exception vti6: PMTU exceptions - pmtu_vti4_default_mtu vti4: default MTU assignment" + pmtu_vti4_default_mtu vti4: default MTU assignment + pmtu_vti6_default_mtu vti6: default MTU assignment" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -225,6 +229,18 @@ test_pmtu_vti4_default_mtu() { fi } +test_pmtu_vti6_default_mtu() { + setup namespaces veth vti6 || return 2 + + # Check that MTU of vti device is MTU of veth minus IPv6 header length + veth_mtu="$(link_get_mtu "${ns_a}" veth_a)" + vti6_mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ $((veth_mtu - vti6_mtu)) -ne 40 ]; then + err " vti MTU ${vti6_mtu} is not veth MTU ${veth_mtu} minus IPv6 header length" + return 1 + fi +} + trap cleanup EXIT exitcode=0 -- cgit v1.2.3 From 5e84430bb83e8241c485ccce728ff5e5e80789eb Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:44 +0100 Subject: selftests: pmtu: Add test_pmtu_vti4_exception test This test checks that PMTU exceptions are created only when needed on IPv4 routes with vti and xfrm, and their PMTU value is checked as well. We can't adopt the same approach as test_pmtu_vti6_exception() here, because on IPv4 administrative MTU changes won't be reflected directly on PMTU. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 80 ++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 5d9af22b360a..ba11433d17d8 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -6,6 +6,14 @@ # # Tests currently implemented: # +# - pmtu_vti4_exception +# Set up vti tunnel on top of veth, with xfrm states and policies, in two +# namespaces with matching endpoints. Check that route exception is not +# created if link layer MTU is not exceeded, then exceed it and check that +# exception is created with the expected PMTU. The approach described +# below for IPv6 doesn't apply here, because, on IPv4, administrative MTU +# changes alone won't affect PMTU +# # - pmtu_vti6_exception # Set up vti6 tunnel on top of veth, with xfrm states and policies, in two # namespaces with matching endpoints. Check that route exception is @@ -24,6 +32,7 @@ tests=" pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment pmtu_vti6_default_mtu vti6: default MTU assignment" @@ -109,15 +118,27 @@ setup_vti6() { } setup_xfrm() { - ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 - ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel - ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel - - ${ns_b} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel - ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + proto=${1} + veth_a_addr="${2}" + veth_b_addr="${3}" + + ${ns_a} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 + ${ns_a} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_a} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel + ${ns_a} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel + + ${ns_b} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel + ${ns_b} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel +} + +setup_xfrm4() { + setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} +} + +setup_xfrm6() { + setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} } setup() { @@ -182,8 +203,47 @@ route_get_dst_pmtu_from_exception() { mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" } +test_pmtu_vti4_exception() { + setup namespaces veth vti4 xfrm4 || return 2 + + veth_mtu=1500 + vti_mtu=$((veth_mtu - 20)) + + # SPI SN IV ICV pad length next header + esp_payload_rfc4106=$((vti_mtu - 4 - 4 - 8 - 16 - 1 - 1)) + ping_payload=$((esp_payload_rfc4106 - 28)) + + mtu "${ns_a}" veth_a ${veth_mtu} + mtu "${ns_b}" veth_b ${veth_mtu} + mtu "${ns_a}" vti4_a ${vti_mtu} + mtu "${ns_b}" vti4_b ${vti_mtu} + + # Send DF packet without exceeding link layer MTU, check that no + # exception is created + ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" + if [ "${pmtu}" != "" ]; then + err " unexpected exception created with PMTU ${pmtu} for IP payload length ${esp_payload_rfc4106}" + return 1 + fi + + # Now exceed link layer MTU by one byte, check that exception is created + ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" + if [ "${pmtu}" = "" ]; then + err " exception not created for IP payload length $((esp_payload_rfc4106 + 1))" + return 1 + fi + + # ...with the right PMTU value + if [ ${pmtu} -ne ${esp_payload_rfc4106} ]; then + err " wrong PMTU ${pmtu} in exception, expected: ${esp_payload_rfc4106}" + return 1 + fi +} + test_pmtu_vti6_exception() { - setup namespaces veth vti6 xfrm || return 2 + setup namespaces veth vti6 xfrm6 || return 2 fail=0 # Create route exception by exceeding link layer MTU -- cgit v1.2.3 From 719e121574497436e39536c2a888b901fbe30cfe Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:45 +0100 Subject: selftests: pmtu: Add pmtu_vti4_link_add_mtu test This test checks that MTU given on vti link creation is actually configured, and that tunnel is not created with an invalid MTU value. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index ba11433d17d8..d9f7ef2c213d 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -29,12 +29,17 @@ # # - pmtu_vti6_default_mtu # Same as above, for IPv6 +# +# - pmtu_vti4_link_add_mtu +# Set up vti4 interface passing MTU value at link creation, check MTU is +# configured, and that link is not created with invalid MTU values tests=" pmtu_vti6_exception vti6: PMTU exceptions pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment - pmtu_vti6_default_mtu vti6: default MTU assignment" + pmtu_vti6_default_mtu vti6: default MTU assignment + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -301,6 +306,44 @@ test_pmtu_vti6_default_mtu() { fi } +test_pmtu_vti4_link_add_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add vti4_a type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 + [ $? -ne 0 ] && err " vti not supported" && return 2 + ${ns_a} ip link del vti4_a + + fail=0 + + min=68 + max=$((65528 - 20)) + # Check invalid values first + for v in $((min - 1)) $((max + 1)); do + ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 2>/dev/null + # This can fail, or MTU can be adjusted to a proper value + [ $? -ne 0 ] && continue + mtu="$(link_get_mtu "${ns_a}" vti4_a)" + if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then + err " vti tunnel created with invalid MTU ${mtu}" + fail=1 + fi + ${ns_a} ip link del vti4_a + done + + # Now check valid values + for v in ${min} 1300 ${max}; do + ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 + mtu="$(link_get_mtu "${ns_a}" vti4_a)" + ${ns_a} ip link del vti4_a + if [ "${mtu}" != "${v}" ]; then + err " vti MTU ${mtu} doesn't match configured value ${v}" + fail=1 + fi + done + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.2.3 From 8b6022fc7839e3ba2255bb264b16b0fffe961212 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:46 +0100 Subject: selftests: pmtu: Add pmtu_vti6_link_add_mtu test Same as pmtu_vti4_link_add_mtu test, but for IPv6. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index d9f7ef2c213d..cd12a1f5c003 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -33,13 +33,17 @@ # - pmtu_vti4_link_add_mtu # Set up vti4 interface passing MTU value at link creation, check MTU is # configured, and that link is not created with invalid MTU values +# +# - pmtu_vti6_link_add_mtu +# Same as above, for IPv6 tests=" pmtu_vti6_exception vti6: PMTU exceptions pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment pmtu_vti6_default_mtu vti6: default MTU assignment - pmtu_vti4_link_add_mtu vti4: MTU setting on link creation" + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation + pmtu_vti6_link_add_mtu vti6: MTU setting on link creation" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -344,6 +348,44 @@ test_pmtu_vti4_link_add_mtu() { return ${fail} } +test_pmtu_vti6_link_add_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add vti6_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 + [ $? -ne 0 ] && err " vti6 not supported" && return 2 + ${ns_a} ip link del vti6_a + + fail=0 + + min=1280 + max=$((65535 - 40)) + # Check invalid values first + for v in $((min - 1)) $((max + 1)); do + ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 2>/dev/null + # This can fail, or MTU can be adjusted to a proper value + [ $? -ne 0 ] && continue + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then + err " vti6 tunnel created with invalid MTU ${v}" + fail=1 + fi + ${ns_a} ip link del vti6_a + done + + # Now check valid values + for v in 1280 1300 $((65535 - 40)); do + ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + ${ns_a} ip link del vti6_a + if [ "${mtu}" != "${v}" ]; then + err " vti6 MTU ${mtu} doesn't match configured value ${v}" + fail=1 + fi + done + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.2.3 From 1fad59ea1c34b14f080725fc4cdfc6160651e371 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:47 +0100 Subject: selftests: pmtu: Add pmtu_vti6_link_change_mtu test This test checks that MTU configured from userspace is used on link creation and changes, and that when it's not passed from userspace, it's calculated properly from the MTU of the lower layer. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 67 +++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index cd12a1f5c003..92197c05bac4 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -36,14 +36,21 @@ # # - pmtu_vti6_link_add_mtu # Same as above, for IPv6 +# +# - pmtu_vti6_link_change_mtu +# Set up two dummy interfaces with different MTUs, create a vti6 tunnel +# and check that configured MTU is used on link creation and changes, and +# that MTU is properly calculated instead when MTU is not configured from +# userspace tests=" - pmtu_vti6_exception vti6: PMTU exceptions - pmtu_vti4_exception vti4: PMTU exceptions - pmtu_vti4_default_mtu vti4: default MTU assignment - pmtu_vti6_default_mtu vti6: default MTU assignment - pmtu_vti4_link_add_mtu vti4: MTU setting on link creation - pmtu_vti6_link_add_mtu vti6: MTU setting on link creation" + pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_exception vti4: PMTU exceptions + pmtu_vti4_default_mtu vti4: default MTU assignment + pmtu_vti6_default_mtu vti6: default MTU assignment + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation + pmtu_vti6_link_add_mtu vti6: MTU setting on link creation + pmtu_vti6_link_change_mtu vti6: MTU changes on link changes" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -64,6 +71,10 @@ vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" +dummy6_0_addr="fc00:1000::0" +dummy6_1_addr="fc00:1001::0" +dummy6_mask="64" + cleanup_done=1 err_buf= @@ -386,6 +397,50 @@ test_pmtu_vti6_link_add_mtu() { return ${fail} } +test_pmtu_vti6_link_change_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add dummy0 mtu 1500 type dummy + [ $? -ne 0 ] && err " dummy not supported" && return 2 + ${ns_a} ip link add dummy1 mtu 3000 type dummy + ${ns_a} ip link set dummy0 up + ${ns_a} ip link set dummy1 up + + ${ns_a} ip addr add ${dummy6_0_addr}/${dummy6_mask} dev dummy0 + ${ns_a} ip addr add ${dummy6_1_addr}/${dummy6_mask} dev dummy1 + + fail=0 + + # Create vti6 interface bound to device, passing MTU, check it + ${ns_a} ip link add vti6_a mtu 1300 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne 1300 ]; then + err " vti6 MTU ${mtu} doesn't match configured value 1300" + fail=1 + fi + + # Move to another device with different MTU, without passing MTU, check + # MTU is adjusted + echo "${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr}" > /dev/kmsg + ${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne $((3000 - 40)) ]; then + err " vti MTU ${mtu} is not dummy MTU 3000 minus IPv6 header length" + fail=1 + fi + + # Move it back, passing MTU, check MTU is not overridden + echo "${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}" > /dev/kmsg + ${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne 1280 ]; then + err " vti6 MTU ${mtu} doesn't match configured value 1280" + fail=1 + fi + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.2.3 From e3c72f3d37e4745dc3a6ae69f5fc2bd4c31ca4eb Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sun, 18 Mar 2018 21:58:12 +0100 Subject: selftests: pmtu: Drop prints to kernel log from pmtu_vti6_link_change_mtu Reported-by: David Ahern Fixes: 1fad59ea1c34 ("selftests: pmtu: Add pmtu_vti6_link_change_mtu test") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 92197c05bac4..1e428781a625 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -421,7 +421,6 @@ test_pmtu_vti6_link_change_mtu() { # Move to another device with different MTU, without passing MTU, check # MTU is adjusted - echo "${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr}" > /dev/kmsg ${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr} mtu="$(link_get_mtu "${ns_a}" vti6_a)" if [ ${mtu} -ne $((3000 - 40)) ]; then @@ -430,7 +429,6 @@ test_pmtu_vti6_link_change_mtu() { fi # Move it back, passing MTU, check MTU is not overridden - echo "${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}" > /dev/kmsg ${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} mtu="$(link_get_mtu "${ns_a}" vti6_a)" if [ ${mtu} -ne 1280 ]; then -- cgit v1.2.3 From 82a8616889d506cb690cfc0afb2ccadda120461d Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:31 -0700 Subject: bpf: add map tests for BPF_PROG_TYPE_SK_MSG Add map tests to attach BPF_PROG_TYPE_SK_MSG types to a sockmap. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 10 ++++ tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + tools/testing/selftests/bpf/sockmap_parse_prog.c | 15 +++++- tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c | 33 +++++++++++++ tools/testing/selftests/bpf/sockmap_verdict_prog.c | 7 +++ tools/testing/selftests/bpf/test_maps.c | 55 ++++++++++++++++++++-- 7 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 1944d0aee7e8..13d9c59d79ce 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -133,6 +133,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SOCK_OPS, BPF_PROG_TYPE_SK_SKB, BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, }; enum bpf_attach_type { @@ -143,6 +144,7 @@ enum bpf_attach_type { BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT, BPF_CGROUP_DEVICE, + BPF_SK_MSG_VERDICT, __MAX_BPF_ATTACH_TYPE }; @@ -941,6 +943,14 @@ enum sk_action { SK_PASS, }; +/* user accessible metadata for SK_MSG packet hook, new fields must + * be added to the end of this structure + */ +struct sk_msg_md { + void *data; + void *data_end; +}; + #define BPF_TAG_SIZE 8 struct bpf_prog_info { diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index b0d29fd5e51c..f35fb02bdf56 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,7 +29,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ - sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o + sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ + sockmap_tcp_msg_prog.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index dde2c11d7771..1558fe8bcf3e 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -123,6 +123,8 @@ static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = (void *) BPF_FUNC_skb_under_cgroup; static int (*bpf_skb_change_head)(void *, int len, int flags) = (void *) BPF_FUNC_skb_change_head; +static int (*bpf_skb_pull_data)(void *, int len) = + (void *) BPF_FUNC_skb_pull_data; /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ #if defined(__TARGET_ARCH_x86) diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c index a1dec2b6d9c5..0f92858f6226 100644 --- a/tools/testing/selftests/bpf/sockmap_parse_prog.c +++ b/tools/testing/selftests/bpf/sockmap_parse_prog.c @@ -20,14 +20,25 @@ int bpf_prog1(struct __sk_buff *skb) __u32 lport = skb->local_port; __u32 rport = skb->remote_port; __u8 *d = data; + __u32 len = (__u32) data_end - (__u32) data; + int err; - if (data + 10 > data_end) - return skb->len; + if (data + 10 > data_end) { + err = bpf_skb_pull_data(skb, 10); + if (err) + return SK_DROP; + + data_end = (void *)(long)skb->data_end; + data = (void *)(long)skb->data; + if (data + 10 > data_end) + return SK_DROP; + } /* This write/read is a bit pointless but tests the verifier and * strparser handler for read/write pkt data and access into sk * fields. */ + d = data; d[7] = 1; return skb->len; } diff --git a/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c b/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c new file mode 100644 index 000000000000..12a7b5c82ed6 --- /dev/null +++ b/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c @@ -0,0 +1,33 @@ +#include +#include "bpf_helpers.h" +#include "bpf_util.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +SEC("sk_msg1") +int bpf_prog1(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + + char *d; + + if (data + 8 > data_end) + return SK_DROP; + + bpf_printk("data length %i\n", (__u64)msg->data_end - (__u64)msg->data); + d = (char *)data; + bpf_printk("hello sendmsg hook %i %i\n", d[0], d[1]); + + return SK_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c index d7bea972cb21..2ce7634a4012 100644 --- a/tools/testing/selftests/bpf/sockmap_verdict_prog.c +++ b/tools/testing/selftests/bpf/sockmap_verdict_prog.c @@ -26,6 +26,13 @@ struct bpf_map_def SEC("maps") sock_map_tx = { .max_entries = 20, }; +struct bpf_map_def SEC("maps") sock_map_msg = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + struct bpf_map_def SEC("maps") sock_map_break = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 1238733c5b33..6c253343a6f9 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -464,15 +464,17 @@ static void test_devmap(int task, void *data) #include #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o" #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" +#define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.o" static void test_sockmap(int tasks, void *data) { - int one = 1, map_fd_rx = 0, map_fd_tx = 0, map_fd_break, s, sc, rc; - struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_break; + struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break; + int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break; int ports[] = {50200, 50201, 50202, 50204}; int err, i, fd, udp, sfd[6] = {0xdeadbeef}; u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0}; - int parse_prog, verdict_prog; + int parse_prog, verdict_prog, msg_prog; struct sockaddr_in addr; + int one = 1, s, sc, rc; struct bpf_object *obj; struct timeval to; __u32 key, value; @@ -584,6 +586,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_attach(-1, fd, BPF_SK_MSG_VERDICT, 0); + if (!err) { + printf("Failed invalid msg verdict prog attach\n"); + goto out_sockmap; + } + err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0); if (!err) { printf("Failed unknown prog attach\n"); @@ -602,6 +610,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT); + if (err) { + printf("Failed empty msg verdict prog detach\n"); + goto out_sockmap; + } + err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE); if (!err) { printf("Detach invalid prog successful\n"); @@ -616,6 +630,13 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_load(SOCKMAP_TCP_MSG_PROG, + BPF_PROG_TYPE_SK_MSG, &obj, &msg_prog); + if (err) { + printf("Failed to load SK_SKB msg prog\n"); + goto out_sockmap; + } + err = bpf_prog_load(SOCKMAP_VERDICT_PROG, BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog); if (err) { @@ -631,7 +652,7 @@ static void test_sockmap(int tasks, void *data) map_fd_rx = bpf_map__fd(bpf_map_rx); if (map_fd_rx < 0) { - printf("Failed to get map fd\n"); + printf("Failed to get map rx fd\n"); goto out_sockmap; } @@ -647,6 +668,18 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + bpf_map_msg = bpf_object__find_map_by_name(obj, "sock_map_msg"); + if (IS_ERR(bpf_map_msg)) { + printf("Failed to load map msg from msg_verdict prog\n"); + goto out_sockmap; + } + + map_fd_msg = bpf_map__fd(bpf_map_msg); + if (map_fd_msg < 0) { + printf("Failed to get map msg fd\n"); + goto out_sockmap; + } + bpf_map_break = bpf_object__find_map_by_name(obj, "sock_map_break"); if (IS_ERR(bpf_map_break)) { printf("Failed to load map tx from verdict prog\n"); @@ -680,6 +713,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_attach(msg_prog, map_fd_msg, BPF_SK_MSG_VERDICT, 0); + if (err) { + printf("Failed msg verdict bpf prog attach\n"); + goto out_sockmap; + } + err = bpf_prog_attach(verdict_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE, 0); if (!err) { @@ -719,6 +758,14 @@ static void test_sockmap(int tasks, void *data) } } + /* Put sfd[2] (sending fd below) into msg map to test sendmsg bpf */ + i = 0; + err = bpf_map_update_elem(map_fd_msg, &i, &sfd[2], BPF_ANY); + if (err) { + printf("Failed map_fd_msg update sockmap %i\n", err); + goto out_sockmap; + } + /* Test map send/recv */ for (i = 0; i < 2; i++) { buf[0] = i; -- cgit v1.2.3 From 1acc60b6a41bd4e43c3cb10e5395a5c812e158f5 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:36 -0700 Subject: bpf: add verifier tests for BPF_PROG_TYPE_SK_MSG Test read and writes for BPF_PROG_TYPE_SK_MSG. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 86d7ff491b6f..3e7718b1a9ae 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1596,6 +1596,60 @@ static struct bpf_test tests[] = { .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SK_SKB, }, + { + "direct packet read for SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, + { + "direct packet write for SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), + BPF_STX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, + { + "overlapping checks for direct packet access SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6), + BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), + BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, { "check skb->mark is not writeable by sockets", .insns = { -- cgit v1.2.3 From 4c4c3c276c099f265c8b11e0132ce826ee718e2c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:41 -0700 Subject: bpf: sockmap sample, add option to attach SK_MSG program Add sockmap option to use SK_MSG program types. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/bpf/bpf_load.c | 8 +++- samples/sockmap/sockmap_kern.c | 52 ++++++++++++++++++++++++ samples/sockmap/sockmap_user.c | 67 ++++++++++++++++++++++++++++--- tools/include/uapi/linux/bpf.h | 13 +++++- tools/lib/bpf/libbpf.c | 1 + tools/testing/selftests/bpf/bpf_helpers.h | 3 ++ 6 files changed, 135 insertions(+), 9 deletions(-) (limited to 'tools/testing') diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 69806d74fa53..b1a310c3ae89 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -67,6 +67,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0; bool is_sockops = strncmp(event, "sockops", 7) == 0; bool is_sk_skb = strncmp(event, "sk_skb", 6) == 0; + bool is_sk_msg = strncmp(event, "sk_msg", 6) == 0; size_t insns_cnt = size / sizeof(struct bpf_insn); enum bpf_prog_type prog_type; char buf[256]; @@ -96,6 +97,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) prog_type = BPF_PROG_TYPE_SOCK_OPS; } else if (is_sk_skb) { prog_type = BPF_PROG_TYPE_SK_SKB; + } else if (is_sk_msg) { + prog_type = BPF_PROG_TYPE_SK_MSG; } else { printf("Unknown event '%s'\n", event); return -1; @@ -113,7 +116,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk) return 0; - if (is_socket || is_sockops || is_sk_skb) { + if (is_socket || is_sockops || is_sk_skb || is_sk_msg) { if (is_socket) event += 6; else @@ -589,7 +592,8 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map) memcmp(shname, "socket", 6) == 0 || memcmp(shname, "cgroup/", 7) == 0 || memcmp(shname, "sockops", 7) == 0 || - memcmp(shname, "sk_skb", 6) == 0) { + memcmp(shname, "sk_skb", 6) == 0 || + memcmp(shname, "sk_msg", 6) == 0) { ret = load_and_attach(shname, data->d_buf, data->d_size); if (ret != 0) diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 52b0053274f4..75edb2f151d4 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -43,6 +43,20 @@ struct bpf_map_def SEC("maps") sock_map = { .max_entries = 20, }; +struct bpf_map_def SEC("maps") sock_map_txmsg = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +struct bpf_map_def SEC("maps") sock_map_redir = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1, +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -105,4 +119,42 @@ int bpf_sockmap(struct bpf_sock_ops *skops) return 0; } + +SEC("sk_msg1") +int bpf_prog4(struct sk_msg_md *msg) +{ + return SK_PASS; +} + +SEC("sk_msg2") +int bpf_prog5(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + + bpf_printk("sk_msg2: data length %i\n", (__u32)data_end - (__u32)data); + return SK_PASS; +} + +SEC("sk_msg3") +int bpf_prog6(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0; + + return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +} + +SEC("sk_msg4") +int bpf_prog7(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0; + + bpf_printk("sk_msg3: redirect(%iB)\n", (__u32)data_end - (__u32)data); + return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +} + char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 95a54a89a532..bbfe3a2b9885 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -54,6 +54,11 @@ void running_handler(int a); /* global sockets */ int s1, s2, c1, c2, p1, p2; +int txmsg_pass; +int txmsg_noisy; +int txmsg_redir; +int txmsg_redir_noisy; + static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, {"cgroup", required_argument, NULL, 'c' }, @@ -62,6 +67,10 @@ static const struct option long_options[] = { {"iov_count", required_argument, NULL, 'i' }, {"length", required_argument, NULL, 'l' }, {"test", required_argument, NULL, 't' }, + {"txmsg", no_argument, &txmsg_pass, 1 }, + {"txmsg_noisy", no_argument, &txmsg_noisy, 1 }, + {"txmsg_redir", no_argument, &txmsg_redir, 1 }, + {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, {0, 0, NULL, 0 } }; @@ -447,13 +456,13 @@ enum { int main(int argc, char **argv) { - int iov_count = 1, length = 1024, rate = 1, verbose = 0; + int iov_count = 1, length = 1024, rate = 1, verbose = 0, tx_prog_fd; struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; int opt, longindex, err, cg_fd = 0; int test = PING_PONG; char filename[256]; - while ((opt = getopt_long(argc, argv, "hvc:r:i:l:t:", + while ((opt = getopt_long(argc, argv, ":hvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { /* Cgroup configuration */ @@ -490,6 +499,8 @@ int main(int argc, char **argv) return -1; } break; + case 0: + break; case 'h': default: usage(argv); @@ -515,16 +526,16 @@ int main(int argc, char **argv) /* catch SIGINT */ signal(SIGINT, running_handler); - /* If base test skip BPF setup */ - if (test == BASE) - goto run; - if (load_bpf_file(filename)) { fprintf(stderr, "load_bpf_file: (%s) %s\n", filename, strerror(errno)); return 1; } + /* If base test skip BPF setup */ + if (test == BASE) + goto run; + /* Attach programs to sockmap */ err = bpf_prog_attach(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER, 0); @@ -557,6 +568,50 @@ run: goto out; } + /* Attach txmsg program to sockmap */ + if (txmsg_pass) + tx_prog_fd = prog_fd[3]; + else if (txmsg_noisy) + tx_prog_fd = prog_fd[4]; + else if (txmsg_redir) + tx_prog_fd = prog_fd[5]; + else if (txmsg_redir_noisy) + tx_prog_fd = prog_fd[6]; + else + tx_prog_fd = 0; + + if (tx_prog_fd) { + int redir_fd, i = 0; + + err = bpf_prog_attach(tx_prog_fd, + map_fd[1], BPF_SK_MSG_VERDICT, 0); + if (err) { + fprintf(stderr, + "ERROR: bpf_prog_attach (txmsg): %d (%s)\n", + err, strerror(errno)); + return err; + } + + err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", + err, strerror(errno)); + return err; + } + if (test == SENDMSG) + redir_fd = c2; + else + redir_fd = c1; + + err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", + err, strerror(errno)); + return err; + } + } if (test == PING_PONG) err = forever_ping_pong(rate, verbose); else if (test == SENDMSG) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 13d9c59d79ce..01b9c97b172e 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -720,6 +720,15 @@ union bpf_attr { * int bpf_override_return(pt_regs, rc) * @pt_regs: pointer to struct pt_regs * @rc: the return value to set + * + * int bpf_msg_redirect_map(map, key, flags) + * Redirect msg to a sock in map using key as a lookup key for the + * sock in map. + * @map: pointer to sockmap + * @key: key to lookup sock in map + * @flags: reserved for future use + * Return: SK_PASS + * */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -781,7 +790,9 @@ union bpf_attr { FN(perf_prog_read_value), \ FN(getsockopt), \ FN(override_return), \ - FN(sock_ops_cb_flags_set), + FN(sock_ops_cb_flags_set), \ + FN(msg_redirect_map), \ + FN(msg_apply_bytes), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 5bbbf285af74..64a8fc384186 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1857,6 +1857,7 @@ static const struct { BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), + BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), }; #undef BPF_PROG_SEC diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 1558fe8bcf3e..bba7ee6d93ab 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -86,6 +86,9 @@ static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, (void *) BPF_FUNC_perf_prog_read_value; static int (*bpf_override_return)(void *ctx, unsigned long rc) = (void *) BPF_FUNC_override_return; +static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = + (void *) BPF_FUNC_msg_redirect_map; + /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.2.3 From 1c16c3126ac938562a68ab7041fe74ce0de53166 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:56 -0700 Subject: bpf: sockmap, add sample option to test apply_bytes helper This adds an option to test the apply_bytes helper. This option lets the user specify an int on the command line specifying how much data each verdict should apply to. When this is set a map entry is set with the bytes input by the user and then the specified program --txmsg or --txmsg_redir will use the value and set the applied data. If no other option is set then a default --txmsg_apply program is run. This program will drop pkts if an error is detected on the bytes map lookup. Useful to verify the map lookup and apply helper are working and causing a hard error if it is not. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 54 +++++++++++++++++++++++++++---- samples/sockmap/sockmap_user.c | 19 ++++++++++- tools/testing/selftests/bpf/bpf_helpers.h | 3 +- 3 files changed, 68 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 75edb2f151d4..205ec36449d1 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -57,6 +57,13 @@ struct bpf_map_def SEC("maps") sock_map_redir = { .max_entries = 1, }; +struct bpf_map_def SEC("maps") sock_apply_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1 +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -123,6 +130,11 @@ int bpf_sockmap(struct bpf_sock_ops *skops) SEC("sk_msg1") int bpf_prog4(struct sk_msg_md *msg) { + int *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + bpf_msg_apply_bytes(msg, *bytes); return SK_PASS; } @@ -131,8 +143,13 @@ int bpf_prog5(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; + int *bytes, err = 0, zero = 0; - bpf_printk("sk_msg2: data length %i\n", (__u32)data_end - (__u32)data); + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + err = bpf_msg_apply_bytes(msg, *bytes); + bpf_printk("sk_msg2: data length %i err %i\n", + (__u64)data_end - (__u64)data, err); return SK_PASS; } @@ -141,9 +158,12 @@ int bpf_prog6(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int ret = 0; + int *bytes, zero = 0; - return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + bpf_msg_apply_bytes(msg, *bytes); + return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } SEC("sk_msg4") @@ -151,10 +171,32 @@ int bpf_prog7(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int ret = 0; + int *bytes, err = 0, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + err = bpf_msg_apply_bytes(msg, *bytes); + bpf_printk("sk_msg3: redirect(%iB) err=%i\n", + (__u64)data_end - (__u64)data, err); + return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); +} - bpf_printk("sk_msg3: redirect(%iB)\n", (__u32)data_end - (__u32)data); - return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +SEC("sk_msg5") +int bpf_prog8(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0, *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) { + ret = bpf_msg_apply_bytes(msg, *bytes); + if (ret) + return SK_DROP; + } else { + return SK_DROP; + } + return SK_PASS; } char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 8017ad7afea9..41774ec0f0b3 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -59,6 +59,7 @@ int txmsg_pass; int txmsg_noisy; int txmsg_redir; int txmsg_redir_noisy; +int txmsg_apply; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -73,6 +74,7 @@ static const struct option long_options[] = { {"txmsg_noisy", no_argument, &txmsg_noisy, 1 }, {"txmsg_redir", no_argument, &txmsg_redir, 1 }, {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, + {"txmsg_apply", required_argument, NULL, 'a'}, {0, 0, NULL, 0 } }; @@ -546,7 +548,9 @@ int main(int argc, char **argv) while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { - /* Cgroup configuration */ + case 'a': + txmsg_apply = atoi(optarg); + break; case 'c': cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); if (cg_fd < 0) { @@ -665,6 +669,8 @@ run: tx_prog_fd = prog_fd[5]; else if (txmsg_redir_noisy) tx_prog_fd = prog_fd[6]; + else if (txmsg_apply) + tx_prog_fd = prog_fd[7]; else tx_prog_fd = 0; @@ -699,6 +705,17 @@ run: err, strerror(errno)); return err; } + + if (txmsg_apply) { + err = bpf_map_update_elem(map_fd[3], + &i, &txmsg_apply, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n", + err, strerror(errno)); + return err; + } + } } if (test == PING_PONG) err = forever_ping_pong(rate, &options); diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index bba7ee6d93ab..4713de48cf88 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -88,7 +88,8 @@ static int (*bpf_override_return)(void *ctx, unsigned long rc) = (void *) BPF_FUNC_override_return; static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = (void *) BPF_FUNC_msg_redirect_map; - +static int (*bpf_msg_apply_bytes)(void *ctx, int len) = + (void *) BPF_FUNC_msg_apply_bytes; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.2.3 From 468b3fdea8826b232a570d95ba45272eb38919cb Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:58:02 -0700 Subject: bpf: sockmap sample support for bpf_msg_cork_bytes() Add sample application support for the bpf_msg_cork_bytes helper. This lets the user specify how many bytes each verdict should apply to. Similar to apply_bytes() tests these can be run as a stand-alone test when used without other options or inline with other tests by using the txmsg_cork option along with any of the basic tests txmsg, txmsg_redir, txmsg_drop. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 53 ++++++++++++++++++++++++++----- samples/sockmap/sockmap_user.c | 19 +++++++++++ tools/include/uapi/linux/bpf.h | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 ++ 4 files changed, 68 insertions(+), 9 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 205ec36449d1..735226794ce1 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -64,6 +64,13 @@ struct bpf_map_def SEC("maps") sock_apply_bytes = { .max_entries = 1 }; +struct bpf_map_def SEC("maps") sock_cork_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1 +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -135,6 +142,9 @@ int bpf_prog4(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + bpf_msg_cork_bytes(msg, *bytes); return SK_PASS; } @@ -143,13 +153,16 @@ int bpf_prog5(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int *bytes, err = 0, zero = 0; + int *bytes, err1 = -1, err2 = -1, zero = 0; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) - err = bpf_msg_apply_bytes(msg, *bytes); - bpf_printk("sk_msg2: data length %i err %i\n", - (__u64)data_end - (__u64)data, err); + err1 = bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + err2 = bpf_msg_cork_bytes(msg, *bytes); + bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", + (__u64)data_end - (__u64)data, err1, err2); return SK_PASS; } @@ -163,6 +176,9 @@ int bpf_prog6(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + bpf_msg_cork_bytes(msg, *bytes); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -171,13 +187,17 @@ int bpf_prog7(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int *bytes, err = 0, zero = 0; + int *bytes, err1 = 0, err2 = 0, zero = 0; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) - err = bpf_msg_apply_bytes(msg, *bytes); - bpf_printk("sk_msg3: redirect(%iB) err=%i\n", - (__u64)data_end - (__u64)data, err); + err1 = bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + err2 = bpf_msg_cork_bytes(msg, *bytes); + + bpf_printk("sk_msg3: redirect(%iB) err1=%i err2=%i\n", + (__u64)data_end - (__u64)data, err1, err2); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -198,5 +218,22 @@ int bpf_prog8(struct sk_msg_md *msg) } return SK_PASS; } +SEC("sk_msg6") +int bpf_prog9(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0, *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) { + if (((__u64)data_end - (__u64)data) >= *bytes) + return SK_PASS; + ret = bpf_msg_cork_bytes(msg, *bytes); + if (ret) + return SK_DROP; + } + return SK_PASS; +} char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 41774ec0f0b3..4e0a3d87881f 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -60,6 +60,7 @@ int txmsg_noisy; int txmsg_redir; int txmsg_redir_noisy; int txmsg_apply; +int txmsg_cork; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -75,6 +76,7 @@ static const struct option long_options[] = { {"txmsg_redir", no_argument, &txmsg_redir, 1 }, {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, {"txmsg_apply", required_argument, NULL, 'a'}, + {"txmsg_cork", required_argument, NULL, 'k'}, {0, 0, NULL, 0 } }; @@ -551,6 +553,9 @@ int main(int argc, char **argv) case 'a': txmsg_apply = atoi(optarg); break; + case 'k': + txmsg_cork = atoi(optarg); + break; case 'c': cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); if (cg_fd < 0) { @@ -671,6 +676,8 @@ run: tx_prog_fd = prog_fd[6]; else if (txmsg_apply) tx_prog_fd = prog_fd[7]; + else if (txmsg_cork) + tx_prog_fd = prog_fd[8]; else tx_prog_fd = 0; @@ -716,6 +723,18 @@ run: return err; } } + + if (txmsg_cork) { + err = bpf_map_update_elem(map_fd[4], + &i, &txmsg_cork, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n", + err, strerror(errno)); + return err; + } + } + } if (test == PING_PONG) err = forever_ping_pong(rate, &options); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 01b9c97b172e..e6924ab20fc3 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -792,7 +792,8 @@ union bpf_attr { FN(override_return), \ FN(sock_ops_cb_flags_set), \ FN(msg_redirect_map), \ - FN(msg_apply_bytes), + FN(msg_apply_bytes), \ + FN(msg_cork_bytes), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 4713de48cf88..b5b45ff705ff 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -90,6 +90,8 @@ static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = (void *) BPF_FUNC_msg_redirect_map; static int (*bpf_msg_apply_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_apply_bytes; +static int (*bpf_msg_cork_bytes)(void *ctx, int len) = + (void *) BPF_FUNC_msg_cork_bytes; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.2.3 From 0dcbbf6785799ba05b44df2ba6bcc1195f4f945c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:58:12 -0700 Subject: bpf: sockmap sample test for bpf_msg_pull_data This adds an option to test the msg_pull_data helper. This uses two options txmsg_start and txmsg_end to let the user specify start and end bytes to pull. The options can be used with txmsg_apply, txmsg_cork options as well as with any of the basic tests, txmsg, txmsg_redir and txmsg_drop (plus noisy variants) to run pull_data inline with those tests. By giving user direct control over the variables we can easily do negative testing as well as positive tests. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 79 +++++++++++++++++++++++++------ samples/sockmap/sockmap_user.c | 32 +++++++++++++ tools/include/uapi/linux/bpf.h | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + 4 files changed, 101 insertions(+), 15 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 8b6c34cd5f46..9ad5ba79c85a 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -71,6 +71,14 @@ struct bpf_map_def SEC("maps") sock_cork_bytes = { .max_entries = 1 }; +struct bpf_map_def SEC("maps") sock_pull_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 2 +}; + + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -137,7 +145,8 @@ int bpf_sockmap(struct bpf_sock_ops *skops) SEC("sk_msg1") int bpf_prog4(struct sk_msg_md *msg) { - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -145,15 +154,18 @@ int bpf_prog4(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); return SK_PASS; } SEC("sk_msg2") int bpf_prog5(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, err1 = -1, err2 = -1, zero = 0; + int err1 = -1, err2 = -1, zero = 0, one = 1; + int *bytes, *start, *end, len1, len2; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -161,17 +173,32 @@ int bpf_prog5(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) err2 = bpf_msg_cork_bytes(msg, *bytes); + len1 = (__u64)msg->data_end - (__u64)msg->data; + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) { + int err; + + bpf_printk("sk_msg2: pull(%i:%i)\n", + start ? *start : 0, end ? *end : 0); + err = bpf_msg_pull_data(msg, *start, *end, 0); + if (err) + bpf_printk("sk_msg2: pull_data err %i\n", + err); + len2 = (__u64)msg->data_end - (__u64)msg->data; + bpf_printk("sk_msg2: length update %i->%i\n", + len1, len2); + } bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", - (__u64)data_end - (__u64)data, err1, err2); + len1, err1, err2); return SK_PASS; } SEC("sk_msg3") int bpf_prog6(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -179,15 +206,18 @@ int bpf_prog6(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } SEC("sk_msg4") int bpf_prog7(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, err1 = 0, err2 = 0, zero = 0; + int err1 = 0, err2 = 0, zero = 0, one = 1; + int *bytes, *start, *end, len1, len2; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -195,9 +225,24 @@ int bpf_prog7(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) err2 = bpf_msg_cork_bytes(msg, *bytes); - + len1 = (__u64)msg->data_end - (__u64)msg->data; + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) { + int err; + + bpf_printk("sk_msg2: pull(%i:%i)\n", + start ? *start : 0, end ? *end : 0); + err = bpf_msg_pull_data(msg, *start, *end, 0); + if (err) + bpf_printk("sk_msg2: pull_data err %i\n", + err); + len2 = (__u64)msg->data_end - (__u64)msg->data; + bpf_printk("sk_msg2: length update %i->%i\n", + len1, len2); + } bpf_printk("sk_msg3: redirect(%iB) err1=%i err2=%i\n", - (__u64)data_end - (__u64)data, err1, err2); + len1, err1, err2); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -239,7 +284,8 @@ int bpf_prog9(struct sk_msg_md *msg) SEC("sk_msg7") int bpf_prog10(struct sk_msg_md *msg) { - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -247,6 +293,11 @@ int bpf_prog10(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); + return SK_DROP; } diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 52c4ed7774d4..07aa237221d1 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -62,6 +62,8 @@ int txmsg_redir_noisy; int txmsg_drop; int txmsg_apply; int txmsg_cork; +int txmsg_start; +int txmsg_end; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -79,6 +81,8 @@ static const struct option long_options[] = { {"txmsg_drop", no_argument, &txmsg_drop, 1 }, {"txmsg_apply", required_argument, NULL, 'a'}, {"txmsg_cork", required_argument, NULL, 'k'}, + {"txmsg_start", required_argument, NULL, 's'}, + {"txmsg_end", required_argument, NULL, 'e'}, {0, 0, NULL, 0 } }; @@ -572,6 +576,12 @@ int main(int argc, char **argv) while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { + case 's': + txmsg_start = atoi(optarg); + break; + case 'e': + txmsg_end = atoi(optarg); + break; case 'a': txmsg_apply = atoi(optarg); break; @@ -761,6 +771,28 @@ run: } } + if (txmsg_start) { + err = bpf_map_update_elem(map_fd[5], + &i, &txmsg_start, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n", + err, strerror(errno)); + return err; + } + } + + if (txmsg_end) { + i = 1; + err = bpf_map_update_elem(map_fd[5], + &i, &txmsg_end, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n", + err, strerror(errno)); + return err; + } + } } if (txmsg_drop) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e6924ab20fc3..d245c41213ac 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -793,7 +793,8 @@ union bpf_attr { FN(sock_ops_cb_flags_set), \ FN(msg_redirect_map), \ FN(msg_apply_bytes), \ - FN(msg_cork_bytes), + FN(msg_cork_bytes), \ + FN(msg_pull_data), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index b5b45ff705ff..7cae376d8d0c 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -92,6 +92,8 @@ static int (*bpf_msg_apply_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_apply_bytes; static int (*bpf_msg_cork_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_cork_bytes; +static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = + (void *) BPF_FUNC_msg_pull_data; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.2.3 From 8ae797aaa845317bddfbf14f4b37514b017045a6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 20 Mar 2018 10:04:30 -0700 Subject: selftests: Add multipath tests for onlink flag Add multipath tests for onlink flag: one test with onlink added to both nexthops, then tests with onlink added to only 1 nexthop. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib-onlink-tests.sh | 98 ++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh index 06b1d7cc12cc..3991ad1a368d 100755 --- a/tools/testing/selftests/net/fib-onlink-tests.sh +++ b/tools/testing/selftests/net/fib-onlink-tests.sh @@ -56,7 +56,8 @@ TEST_NET6[2]=2001:db8:102 # connected gateway CONGW[1]=169.254.1.254 -CONGW[2]=169.254.5.254 +CONGW[2]=169.254.3.254 +CONGW[3]=169.254.5.254 # recursive gateway RECGW4[1]=169.254.11.254 @@ -232,6 +233,23 @@ run_ip() log_test $? ${exp_rc} "${desc}" } +run_ip_mpath() +{ + local table="$1" + local prefix="$2" + local nh1="$3" + local nh2="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip ro add table "${table}" "${prefix}"/32 \ + nexthop via ${nh1} nexthop via ${nh2} + log_test $? ${exp_rc} "${desc}" +} + valid_onlink_ipv4() { # - unicast connected, unicast recursive @@ -243,13 +261,37 @@ valid_onlink_ipv4() log_subsection "VRF ${VRF}" - run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" log_subsection "VRF device, PBR table" - run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" + + # multipath version + # + log_subsection "default VRF - main table - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.5 \ + "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ + "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.6 \ + "${RECGW4[1]} dev ${NETIFS[p1]} onlink" \ + "${RECGW4[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast recursive - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.7 \ + "${CONGW[1]} dev ${NETIFS[p1]}" \ + "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink first only" + + run_ip_mpath 254 ${TEST_NET4[1]}.8 \ + "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ + "${CONGW[2]} dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink second only" } invalid_onlink_ipv4() @@ -289,6 +331,21 @@ run_ip6() log_test $? ${exp_rc} "${desc}" } +run_ip6_mpath() +{ + local table="$1" + local prefix="$2" + local opts="$3" + local nh1="$4" + local nh2="$5" + local exp_rc="$6" + local desc="$7" + + run_cmd ip -6 ro add table "${table}" "${prefix}"/128 "${opts}" \ + nexthop via ${nh1} nexthop via ${nh2} + log_test $? ${exp_rc} "${desc}" +} + valid_onlink_ipv6() { # - unicast connected, unicast recursive, v4-mapped @@ -310,6 +367,40 @@ valid_onlink_ipv6() run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" + + # multipath version + # + log_subsection "default VRF - main table - multipath" + + run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \ + "${RECGW6[1]} dev ${NETIFS[p1]}" \ + "${RECGW6[2]} dev ${NETIFS[p3]}" \ + 0 "unicast recursive - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \ + "::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \ + "::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \ + 0 "v4-mapped - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink both nexthops" + + run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink first only" + + run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink second only" } invalid_onlink_ipv6() @@ -355,6 +446,7 @@ run_onlink_tests() log_section "IPv6 onlink" log_subsection "Valid onlink commands" valid_onlink_ipv6 + log_subsection "Invalid onlink commands" invalid_onlink_ipv6 } -- cgit v1.2.3 From 440ea4ae182820cfced77cee2b7f3e6eaa8ac5d3 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 22 Mar 2018 19:12:19 +0100 Subject: tc-testing: add selftests for 'bpf' action Test d959: Add cBPF action with valid bytecode Test f84a: Add cBPF action with invalid bytecode Test e939: Add eBPF action with valid object-file Test 282d: Add eBPF action with invalid object-file Test d819: Replace cBPF bytecode and action control Test 6ae3: Delete cBPF action Test 3e0d: List cBPF actions Test 55ce: Flush BPF actions Test ccc3: Add cBPF action with duplicate index Test 89c7: Add cBPF action with invalid index Test 7ab9: Add cBPF action with cookie Changes since v1: - use index=2^32-1 in test ccc3, add tests 7a89, 89c7 (thanks Roman Mashak) - added test 282d Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- .../selftests/tc-testing/tc-tests/actions/bpf.json | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json new file mode 100644 index 000000000000..5b012f4981d4 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json @@ -0,0 +1,289 @@ +[ + { + "id": "d959", + "name": "Add cBPF action with valid bytecode", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 100", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 100", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 100 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "f84a", + "name": "Add cBPF action with invalid bytecode", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,31 0 1 2048,6 0 0 262144,6 0 0 0' index 100", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 100", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,31 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 100 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "e939", + "name": "Add eBPF action with valid object-file", + "category": [ + "actions", + "bpf" + ], + "setup": [ + "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { return 2; }' | clang -O2 -x c -c - -target bpf -o _b.o", + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf object-file _b.o index 667", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 667", + "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9]* tag 3b185187f1855c4c default-action pipe.*index 667 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf", + "rm -f _b.o" + ] + }, + { + "id": "282d", + "name": "Add eBPF action with invalid object-file", + "category": [ + "actions", + "bpf" + ], + "setup": [ + "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { s->data = 0x0; return 2; }' | clang -O2 -x c -c - -target bpf -o _c.o", + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf object-file _c.o index 667", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 667", + "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9].*index 667 ref", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf", + "rm -f _c.o" + ] + }, + { + "id": "d819", + "name": "Replace cBPF bytecode and action control", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + [ + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 555", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action replace action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 555", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 555", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' default-action drop.*index 555 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "6ae3", + "name": "Delete cBPF action ", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + [ + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 444", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action delete action bpf index 444", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 444", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 444 ref", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "3e0d", + "name": "List cBPF actions", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' ok index 101", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 102", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 33024,6 0 0 262144,6 0 0 0' continue index 103" + ], + "cmdUnderTest": "$TC action list action bpf", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode", + "matchCount": "3", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "55ce", + "name": "Flush BPF actions", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' ok index 101", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 102", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 33024,6 0 0 262144,6 0 0 0' continue index 103" + ], + "cmdUnderTest": "$TC action flush action bpf", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode", + "matchCount": "0", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "ccc3", + "name": "Add cBPF action with duplicate index", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 4294967295" + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' index 4294967295", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 4294967295", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 4294967295", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "89c7", + "name": "Add cBPF action with invalid index", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' index 4294967296 cookie 12345", + "expExitCode": "255", + "verifyCmd": "$TC action ls action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*cookie 12345", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "7ab9", + "name": "Add cBPF action with cookie", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' cookie d0d0d0d0d0d0d0d0", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf.*cookie d0d0d0d0d0d0d0", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + } +] -- cgit v1.2.3 From 808679e7fa8018321ccfb227628175b84d2a5ff9 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 25 Mar 2018 17:20:06 -0400 Subject: tc-testing: updated police, mirred, skbedit and skbmod with more tests Added extra test cases for control actions (reclassify, pipe etc.), cookies, max index value and police args sanity check. Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/mirred.json | 192 +++++++++++++++++++++ .../tc-testing/tc-tests/actions/police.json | 144 ++++++++++++++++ .../tc-testing/tc-tests/actions/skbedit.json | 168 ++++++++++++++++++ .../tc-testing/tc-tests/actions/skbmod.json | 24 +++ 4 files changed, 528 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json index 0fcccf18399b..443c9b3c8664 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json @@ -170,6 +170,198 @@ "$TC actions flush action mirred" ] }, + { + "id": "8917", + "name": "Add mirred mirror action with control pass", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pass index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 1", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "1054", + "name": "Add mirred mirror action with control pipe", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pipe index 15", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 15", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pipe.*index 15 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "9887", + "name": "Add mirred mirror action with control continue", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo continue index 15", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 15", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) continue.*index 15 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "e4aa", + "name": "Add mirred mirror action with control reclassify", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo reclassify index 150", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 150", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) reclassify.*index 150 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "ece9", + "name": "Add mirred mirror action with control drop", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo drop index 99", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 99", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) drop.*index 99 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "0031", + "name": "Add mirred mirror action with control jump", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo jump 10 index 99", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 99", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) jump 10.*index 99 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "407c", + "name": "Add mirred mirror action with cookie", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo reclassify cookie aa11bb22cc33dd44ee55", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action mirred", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) reclassify.*cookie aa11bb22cc33dd44ee55", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "8b69", + "name": "Add mirred mirror action with maximum index", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pipe index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 4294967295", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pipe.*index 4294967295", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, { "id": "a70e", "name": "Delete mirred mirror action", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json index 0e602a3f9393..38d85a1d7492 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json @@ -264,6 +264,150 @@ "$TC actions flush action police" ] }, + { + "id": "ddd6", + "name": "Add police action with invalid rate value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 3tb burst 250k conform-exceed pass/pipe index 5", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x5 rate 3Tb burst 250Kb mtu 2Kb action pass/pipe", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "f61c", + "name": "Add police action with invalid burst value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 3kbit burst 250P conform-exceed pass/pipe index 5", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x5 rate 3Kbit burst 250Pb mtu 2Kb action pass/pipe", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "c26f", + "name": "Add police action with invalid peakrate value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 90kbit burst 10k mtu 2kb peakrate 100T index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x1 rate 90Kbit burst 10Kb mtu 2Kb peakrate 100Tbit", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "db04", + "name": "Add police action with invalid mtu value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10kbit burst 10k mtu 2Pbit index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x1 rate 10Kbit burst 1Kb mtu 2Pb", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "f3c9", + "name": "Add police action with cookie", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10mbit burst 10k index 1 cookie a1b1c1d1e1f12233bb", + "expExitCode": "0", + "verifyCmd": "$TC actions get action police index 1", + "matchPattern": "action order [0-9]*: police 0x1 rate 10Mbit burst 10Kb mtu 2Kb.*cookie a1b1c1d1e1f12233bb", + "matchCount": "1", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "d190", + "name": "Add police action with maximum index", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10mbit burst 10k index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 4294967295", + "matchPattern": "action order [0-9]*: police 0xffffffff rate 10Mbit burst 10Kb mtu 2Kb", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, { "id": "336e", "name": "Delete police action", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json index 99635ea4722e..37ecc2716fee 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json @@ -215,6 +215,174 @@ "$TC actions flush action skbedit" ] }, + { + "id": "464a", + "name": "Add skbedit action with control pipe", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 11", + "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "212f", + "name": "Add skbedit action with control reclassify", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 90", + "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "0651", + "name": "Add skbedit action with control pass", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 271", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "cc53", + "name": "Add skbedit action with control drop", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 271", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "ec16", + "name": "Add skbedit action with control jump", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 2", + "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "db54", + "name": "Add skbedit action with control continue", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 32", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "1055", + "name": "Add skbedit action with cookie", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 32", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, { "id": "5172", "name": "List skbedit actions", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json index 90bba48c3f07..fe3326e939c1 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json @@ -263,6 +263,30 @@ "$TC actions flush action skbmod" ] }, + { + "id": "6046", + "name": "Add skbmod action with control reclassify and cookie", + "category": [ + "actions", + "skbmod" + ], + "setup": [ + [ + "$TC actions flush action skbmod", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbmod set smac 00:01:02:03:04:01 reclassify index 1 cookie ddeeffaabb11cc22", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbmod index 1", + "matchPattern": "action order [0-9]*: skbmod reclassify set smac 00:01:02:03:04:01.*index 1 ref.*cookie ddeeffaabb11cc22", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbmod" + ] + }, { "id": "58cb", "name": "List skbmod actions", -- cgit v1.2.3 From cd464197f2378499db134d6c44af3b4e3c0c14b5 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Mon, 26 Mar 2018 10:46:14 -0400 Subject: tc-testing: Correct compound statements for namespace execution If tdc is executing test cases inside a namespace, only the first command in a compound statement will be executed inside the namespace by tdc. As a result, the subsequent commands are not executed inside the namespace and the test will fail. Example: for i in {x..y}; do args="foo"; done && tc actions add $args The namespace execution feature will prepend 'ip netns exec' to the command: ip netns exec tcut for i in {x..y}; do args="foo"; done && \ tc actions add $args So the actual tc command is not parsed by the shell as being part of the namespace execution. Enclosing these compound statements inside a bash invocation with proper escape characters resolves the problem by creating a subshell inside the namespace. Signed-off-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tc-tests/actions/gact.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json index ae96d0350d7e..68c91023cdb9 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json @@ -481,7 +481,7 @@ 255 ] ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action pass index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action pass index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", @@ -505,7 +505,7 @@ 255 ] ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action continue index $i cookie aabbccddeeff112233445566778800a1 \"; args=\"$args$cmd\"; done && $TC actions add $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action continue index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", @@ -528,13 +528,13 @@ 1, 255 ], - "for i in `seq 1 32`; do cmd=\"action continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args" + "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action continue index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\"" ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action gact index $i \"; args=\"$args$cmd\"; done && $TC actions del $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action gact index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", "matchCount": "0", "teardown": [] } -] \ No newline at end of file +] -- cgit v1.2.3 From 3bbe0869884ceebffd59d5519c1d560207c6e116 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 28 Mar 2018 12:05:40 -0700 Subject: selftests/bpf: test for bpf_get_stackid() from raw tracepoints similar to traditional traceopint test add bpf_get_stackid() test from raw tracepoints and reduce verbosity of existing stackmap test Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_progs.c | 91 ++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 21 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index e9df48b306df..faadbe233966 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -877,7 +877,7 @@ static void test_stacktrace_map() err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) - goto out; + return; /* Get the ID for the sched/sched_switch tracepoint */ snprintf(buf, sizeof(buf), @@ -888,8 +888,7 @@ static void test_stacktrace_map() bytes = read(efd, buf, sizeof(buf)); close(efd); - if (CHECK(bytes <= 0 || bytes >= sizeof(buf), - "read", "bytes %d errno %d\n", bytes, errno)) + if (bytes <= 0 || bytes >= sizeof(buf)) goto close_prog; /* Open the perf event and attach bpf progrram */ @@ -906,29 +905,24 @@ static void test_stacktrace_map() goto close_prog; err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); - if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", - err, errno)) - goto close_pmu; + if (err) + goto disable_pmu; err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); - if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", - err, errno)) + if (err) goto disable_pmu; /* find map fds */ control_map_fd = bpf_find_map(__func__, obj, "control_map"); - if (CHECK(control_map_fd < 0, "bpf_find_map control_map", - "err %d errno %d\n", err, errno)) + if (control_map_fd < 0) goto disable_pmu; stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); - if (CHECK(stackid_hmap_fd < 0, "bpf_find_map stackid_hmap", - "err %d errno %d\n", err, errno)) + if (stackid_hmap_fd < 0) goto disable_pmu; stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); - if (CHECK(stackmap_fd < 0, "bpf_find_map stackmap", "err %d errno %d\n", - err, errno)) + if (stackmap_fd < 0) goto disable_pmu; /* give some time for bpf program run */ @@ -945,24 +939,78 @@ static void test_stacktrace_map() err = compare_map_keys(stackid_hmap_fd, stackmap_fd); if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", "err %d errno %d\n", err, errno)) - goto disable_pmu; + goto disable_pmu_noerr; err = compare_map_keys(stackmap_fd, stackid_hmap_fd); if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", "err %d errno %d\n", err, errno)) - ; /* fall through */ + goto disable_pmu_noerr; + goto disable_pmu_noerr; disable_pmu: + error_cnt++; +disable_pmu_noerr: ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); - -close_pmu: close(pmu_fd); - close_prog: bpf_object__close(obj); +} -out: - return; +static void test_stacktrace_map_raw_tp() +{ + int control_map_fd, stackid_hmap_fd, stackmap_fd; + const char *file = "./test_stacktrace_map.o"; + int efd, err, prog_fd; + __u32 key, val, duration = 0; + struct bpf_object *obj; + + err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd); + if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno)) + return; + + efd = bpf_raw_tracepoint_open("sched_switch", prog_fd); + if (CHECK(efd < 0, "raw_tp_open", "err %d errno %d\n", efd, errno)) + goto close_prog; + + /* find map fds */ + control_map_fd = bpf_find_map(__func__, obj, "control_map"); + if (control_map_fd < 0) + goto close_prog; + + stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); + if (stackid_hmap_fd < 0) + goto close_prog; + + stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); + if (stackmap_fd < 0) + goto close_prog; + + /* give some time for bpf program run */ + sleep(1); + + /* disable stack trace collection */ + key = 0; + val = 1; + bpf_map_update_elem(control_map_fd, &key, &val, 0); + + /* for every element in stackid_hmap, we can find a corresponding one + * in stackmap, and vise versa. + */ + err = compare_map_keys(stackid_hmap_fd, stackmap_fd); + if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", + "err %d errno %d\n", err, errno)) + goto close_prog; + + err = compare_map_keys(stackmap_fd, stackid_hmap_fd); + if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", + "err %d errno %d\n", err, errno)) + goto close_prog; + + goto close_prog_noerr; +close_prog: + error_cnt++; +close_prog_noerr: + bpf_object__close(obj); } static int extract_build_id(char *build_id, size_t size) @@ -1138,6 +1186,7 @@ int main(void) test_tp_attach_query(); test_stacktrace_map(); test_stacktrace_build_id(); + test_stacktrace_map_raw_tp(); printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.2.3 From 1dad0f9ffff735ca09ea1588a9c279a45c8978be Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 29 Mar 2018 08:52:37 -0400 Subject: tc-testing: add connmark action tests Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/connmark.json | 291 +++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json new file mode 100644 index 000000000000..70952bd98ff9 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json @@ -0,0 +1,291 @@ +[ + { + "id": "2002", + "name": "Add valid connmark action with defaults", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "56a5", + "name": "Add valid connmark action with control pass", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark pass index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "7c66", + "name": "Add valid connmark action with control drop", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark drop index 100", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 100", + "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "a913", + "name": "Add valid connmark action with control pipe", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark pipe index 455", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 455", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "bdd8", + "name": "Add valid connmark action with control reclassify", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark reclassify index 7", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "b8be", + "name": "Add valid connmark action with control continue", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark continue index 17", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "d8a6", + "name": "Add valid connmark action with control jump", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark jump 10 index 17", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "aae8", + "name": "Add valid connmark action with zone argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "2f0b", + "name": "Add valid connmark action with invalid zone argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21", + "expExitCode": "255", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "9305", + "name": "Add connmark action with unsupported argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2", + "expExitCode": "255", + "verifyCmd": "$TC actions get action connmark index 2", + "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "71ca", + "name": "Add valid connmark action and replace it", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ], + "$TC actions add action connmark zone 777 pass index 555" + ], + "cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 555", + "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "5f8f", + "name": "Add valid connmark action with cookie", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 5", + "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + } +] -- cgit v1.2.3 From c0b6edef0bf0e33c12eaf80c676ff09def011518 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Thu, 29 Mar 2018 15:58:10 -0400 Subject: tc-testing: Add newline when writing test case files When using the -i feature to generate random ID numbers for test cases in tdc, the function that writes the JSON to file doesn't add a newline character to the end of the file, so we have to add our own. Signed-off-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 44de4a272a11..87a04a8a5945 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -490,6 +490,7 @@ def generate_case_ids(alltests): testlist.append(t) outfile = open(f, "w") json.dump(testlist, outfile, indent=4) + outfile.write("\n") outfile.close() def filter_tests_by_id(args, testlist): -- cgit v1.2.3 From e50b0a6f089308bec6b2d0198abed231dee4d277 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:03 -0700 Subject: selftests/bpf: Selftest for sys_bind hooks Add selftest to work with bpf_sock_addr context from `BPF_PROG_TYPE_CGROUP_SOCK_ADDR` programs. Try to bind(2) on IP:port and apply: * loads to make sure context can be read correctly, including narrow loads (byte, half) for IP and full-size loads (word) for all fields; * stores to those fields allowed by verifier. All combination from IPv4/IPv6 and TCP/UDP are tested. Both scenarios are tested: * valid programs can be loaded and attached; * invalid programs can be neither loaded nor attached. Test passes when expected data can be read from context in the BPF-program, and after the call to bind(2) socket is bound to IP:port pair that was written by BPF-program to the context. Example: # ./test_sock_addr Attached bind4 program. Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Attached bind6 program. Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) ### SUCCESS Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 23 ++ tools/lib/bpf/libbpf.c | 6 + tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/test_sock_addr.c | 486 +++++++++++++++++++++++++++ 4 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_sock_addr.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e1c1fed63396..f2120c5c0578 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -136,6 +136,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_DEVICE, BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR, }; enum bpf_attach_type { @@ -147,6 +148,8 @@ enum bpf_attach_type { BPF_SK_SKB_STREAM_VERDICT, BPF_CGROUP_DEVICE, BPF_SK_MSG_VERDICT, + BPF_CGROUP_INET4_BIND, + BPF_CGROUP_INET6_BIND, __MAX_BPF_ATTACH_TYPE }; @@ -1009,6 +1012,26 @@ struct bpf_map_info { __u64 netns_ino; } __attribute__((aligned(8))); +/* User bpf_sock_addr struct to access socket fields and sockaddr struct passed + * by user and intended to be used by socket (e.g. to bind to, depends on + * attach attach type). + */ +struct bpf_sock_addr { + __u32 user_family; /* Allows 4-byte read, but no write. */ + __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write. + * Stored in network byte order. + */ + __u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. + * Stored in network byte order. + */ + __u32 user_port; /* Allows 4-byte read and write. + * Stored in network byte order + */ + __u32 family; /* Allows 4-byte read, but no write */ + __u32 type; /* Allows 4-byte read, but no write */ + __u32 protocol; /* Allows 4-byte read, but no write */ +}; + /* User bpf_sock_ops struct to access socket values and specify request ops * and their replies. * Some of this fields are in network (bigendian) byte order and may need diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 48e3e743ebf7..d7ce8818982c 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1859,6 +1859,9 @@ static void bpf_program__set_expected_attach_type(struct bpf_program *prog, #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) +#define BPF_SA_PROG_SEC(string, ptype) \ + BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) + static const struct { const char *sec; size_t len; @@ -1882,10 +1885,13 @@ static const struct { BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), + BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), + BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), }; #undef BPF_PROG_SEC #undef BPF_PROG_SEC_FULL +#undef BPF_SA_PROG_SEC static int bpf_program__identify_section(struct bpf_program *prog) { diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f35fb02bdf56..f4717c910874 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,7 @@ urandom_read: urandom_read.c # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log test_dev_cgroup test_tcpbpf_user + test_align test_verifier_log test_dev_cgroup test_tcpbpf_user test_sock_addr TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -51,6 +51,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c +$(OUTPUT)/test_sock_addr: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c new file mode 100644 index 000000000000..a57e13a65e37 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "cgroup_helpers.h" + +#define CG_PATH "/foo" + +#define SERV4_IP "192.168.1.254" +#define SERV4_REWRITE_IP "127.0.0.1" +#define SERV4_PORT 4040 +#define SERV4_REWRITE_PORT 4444 + +#define SERV6_IP "face:b00c:1234:5678::abcd" +#define SERV6_REWRITE_IP "::1" +#define SERV6_PORT 6060 +#define SERV6_REWRITE_PORT 6666 + +#define INET_NTOP_BUF 40 + +typedef int (*load_fn)(enum bpf_attach_type, const char *comment); +typedef int (*info_fn)(int, struct sockaddr *, socklen_t *); + +struct program { + enum bpf_attach_type type; + load_fn loadfn; + int fd; + const char *name; + enum bpf_attach_type invalid_type; +}; + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +static int mk_sockaddr(int domain, const char *ip, unsigned short port, + struct sockaddr *addr, socklen_t addr_len) +{ + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + + if (domain != AF_INET && domain != AF_INET6) { + log_err("Unsupported address family"); + return -1; + } + + memset(addr, 0, addr_len); + + if (domain == AF_INET) { + if (addr_len < sizeof(struct sockaddr_in)) + return -1; + addr4 = (struct sockaddr_in *)addr; + addr4->sin_family = domain; + addr4->sin_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) { + log_err("Invalid IPv4: %s", ip); + return -1; + } + } else if (domain == AF_INET6) { + if (addr_len < sizeof(struct sockaddr_in6)) + return -1; + addr6 = (struct sockaddr_in6 *)addr; + addr6->sin6_family = domain; + addr6->sin6_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) { + log_err("Invalid IPv6: %s", ip); + return -1; + } + } + + return 0; +} + +static int load_insns(enum bpf_attach_type attach_type, + const struct bpf_insn *insns, size_t insns_cnt, + const char *comment) +{ + struct bpf_load_program_attr load_attr; + int ret; + + memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); + load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; + load_attr.expected_attach_type = attach_type; + load_attr.insns = insns; + load_attr.insns_cnt = insns_cnt; + load_attr.license = "GPL"; + + ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE); + if (ret < 0 && comment) { + log_err(">>> Loading %s program error.\n" + ">>> Output from verifier:\n%s\n-------\n", + comment, bpf_log_buf); + } + + return ret; +} + +/* [1] These testing programs try to read different context fields, including + * narrow loads of different sizes from user_ip4 and user_ip6, and write to + * those allowed to be overridden. + * + * [2] BPF_LD_IMM64 & BPF_JMP_REG are used below whenever there is a need to + * compare a register with unsigned 32bit integer. BPF_JMP_IMM can't be used + * in such cases since it accepts only _signed_ 32bit integer as IMM + * argument. Also note that BPF_LD_IMM64 contains 2 instructions what matters + * to count jumps properly. + */ + +static int bind4_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + union { + uint8_t u4_addr8[4]; + uint16_t u4_addr16[2]; + uint32_t u4_addr32; + } ip4; + struct sockaddr_in addr4_rw; + + if (inet_pton(AF_INET, SERV4_IP, (void *)&ip4) != 1) { + log_err("Invalid IPv4: %s", SERV4_IP); + return -1; + } + + if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT, + (struct sockaddr *)&addr4_rw, sizeof(addr4_rw)) == -1) + return -1; + + /* See [1]. */ + struct bpf_insn insns[] = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (sk.family == AF_INET && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, family)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 16), + + /* (sk.type == SOCK_DGRAM || sk.type == SOCK_STREAM) && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, type)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 1), + BPF_JMP_A(1), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_STREAM, 12), + + /* 1st_byte_of_user_ip4 == expected && */ + BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[0], 10), + + /* 1st_half_of_user_ip4 == expected && */ + BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[0], 8), + + /* whole_user_ip4 == expected) { */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_LD_IMM64(BPF_REG_8, ip4.u4_addr32), /* See [2]. */ + BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 4), + + /* user_ip4 = addr4_rw.sin_addr */ + BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_addr.s_addr), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_ip4)), + + /* user_port = addr4_rw.sin_port */ + BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_port), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_port)), + /* } */ + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }; + + return load_insns(attach_type, insns, + sizeof(insns) / sizeof(struct bpf_insn), comment); +} + +static int bind6_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + struct sockaddr_in6 addr6_rw; + struct in6_addr ip6; + + if (inet_pton(AF_INET6, SERV6_IP, (void *)&ip6) != 1) { + log_err("Invalid IPv6: %s", SERV6_IP); + return -1; + } + + if (mk_sockaddr(AF_INET6, SERV6_REWRITE_IP, SERV6_REWRITE_PORT, + (struct sockaddr *)&addr6_rw, sizeof(addr6_rw)) == -1) + return -1; + + /* See [1]. */ + struct bpf_insn insns[] = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (sk.family == AF_INET6 && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, family)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18), + + /* 5th_byte_of_user_ip6 == expected && */ + BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[1])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr[4], 16), + + /* 3rd_half_of_user_ip6 == expected && */ + BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[1])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr16[2], 14), + + /* last_word_of_user_ip6 == expected) { */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[3])), + BPF_LD_IMM64(BPF_REG_8, ip6.s6_addr32[3]), /* See [2]. */ + BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 10), + + +#define STORE_IPV6_WORD(N) \ + BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_addr.s6_addr32[N]), \ + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \ + offsetof(struct bpf_sock_addr, user_ip6[N])) + + /* user_ip6 = addr6_rw.sin6_addr */ + STORE_IPV6_WORD(0), + STORE_IPV6_WORD(1), + STORE_IPV6_WORD(2), + STORE_IPV6_WORD(3), + + /* user_port = addr6_rw.sin6_port */ + BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_port), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_port)), + + /* } */ + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }; + + return load_insns(attach_type, insns, + sizeof(insns) / sizeof(struct bpf_insn), comment); +} + +static void print_ip_port(int sockfd, info_fn fn, const char *fmt) +{ + char addr_buf[INET_NTOP_BUF]; + struct sockaddr_storage addr; + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + socklen_t addr_len; + unsigned short port; + void *nip; + + addr_len = sizeof(struct sockaddr_storage); + memset(&addr, 0, addr_len); + + if (fn(sockfd, (struct sockaddr *)&addr, (socklen_t *)&addr_len) == 0) { + if (addr.ss_family == AF_INET) { + addr4 = (struct sockaddr_in *)&addr; + nip = (void *)&addr4->sin_addr; + port = ntohs(addr4->sin_port); + } else if (addr.ss_family == AF_INET6) { + addr6 = (struct sockaddr_in6 *)&addr; + nip = (void *)&addr6->sin6_addr; + port = ntohs(addr6->sin6_port); + } else { + return; + } + const char *addr_str = + inet_ntop(addr.ss_family, nip, addr_buf, INET_NTOP_BUF); + printf(fmt, addr_str ? addr_str : "??", port); + } +} + +static void print_local_ip_port(int sockfd, const char *fmt) +{ + print_ip_port(sockfd, getsockname, fmt); +} + +static int start_server(int type, const struct sockaddr_storage *addr, + socklen_t addr_len) +{ + + int fd; + + fd = socket(addr->ss_family, type, 0); + if (fd == -1) { + log_err("Failed to create server socket"); + goto out; + } + + if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) { + log_err("Failed to bind server socket"); + goto close_out; + } + + if (type == SOCK_STREAM) { + if (listen(fd, 128) == -1) { + log_err("Failed to listen on server socket"); + goto close_out; + } + } + + print_local_ip_port(fd, "\t Actual: bind(%s, %d)\n"); + + goto out; +close_out: + close(fd); + fd = -1; +out: + return fd; +} + +static void print_test_case_num(int domain, int type) +{ + static int test_num; + + printf("Test case #%d (%s/%s):\n", ++test_num, + (domain == AF_INET ? "IPv4" : + domain == AF_INET6 ? "IPv6" : + "unknown_domain"), + (type == SOCK_STREAM ? "TCP" : + type == SOCK_DGRAM ? "UDP" : + "unknown_type")); +} + +static int run_test_case(int domain, int type, const char *ip, + unsigned short port) +{ + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + int servfd = -1; + int err = 0; + + print_test_case_num(domain, type); + + if (mk_sockaddr(domain, ip, port, (struct sockaddr *)&addr, + addr_len) == -1) + return -1; + + printf("\tRequested: bind(%s, %d) ..\n", ip, port); + servfd = start_server(type, &addr, addr_len); + if (servfd == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(servfd); + return err; +} + +static void close_progs_fds(struct program *progs, size_t prog_cnt) +{ + size_t i; + + for (i = 0; i < prog_cnt; ++i) { + close(progs[i].fd); + progs[i].fd = -1; + } +} + +static int load_and_attach_progs(int cgfd, struct program *progs, + size_t prog_cnt) +{ + size_t i; + + for (i = 0; i < prog_cnt; ++i) { + progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL); + if (progs[i].fd != -1) { + log_err("Load with invalid type accepted for %s", + progs[i].name); + goto err; + } + progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name); + if (progs[i].fd == -1) { + log_err("Failed to load program %s", progs[i].name); + goto err; + } + if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type, + BPF_F_ALLOW_OVERRIDE) != -1) { + log_err("Attach with invalid type accepted for %s", + progs[i].name); + goto err; + } + if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type, + BPF_F_ALLOW_OVERRIDE) == -1) { + log_err("Failed to attach program %s", progs[i].name); + goto err; + } + printf("Attached %s program.\n", progs[i].name); + } + + return 0; +err: + close_progs_fds(progs, prog_cnt); + return -1; +} + +static int run_domain_test(int domain, int cgfd, struct program *progs, + size_t prog_cnt, const char *ip, unsigned short port) +{ + int err = 0; + + if (load_and_attach_progs(cgfd, progs, prog_cnt) == -1) + goto err; + + if (run_test_case(domain, SOCK_STREAM, ip, port) == -1) + goto err; + + if (run_test_case(domain, SOCK_DGRAM, ip, port) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close_progs_fds(progs, prog_cnt); + return err; +} + +static int run_test(void) +{ + size_t inet6_prog_cnt; + size_t inet_prog_cnt; + int cgfd = -1; + int err = 0; + + struct program inet6_progs[] = { + {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6", + BPF_CGROUP_INET4_BIND}, + }; + inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program); + + struct program inet_progs[] = { + {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4", + BPF_CGROUP_INET6_BIND}, + }; + inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program); + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CG_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CG_PATH)) + goto err; + + if (run_domain_test(AF_INET, cgfd, inet_progs, inet_prog_cnt, SERV4_IP, + SERV4_PORT) == -1) + goto err; + + if (run_domain_test(AF_INET6, cgfd, inet6_progs, inet6_prog_cnt, + SERV6_IP, SERV6_PORT) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + printf(err ? "### FAIL\n" : "### SUCCESS\n"); + return err; +} + +int main(int argc, char **argv) +{ + return run_test(); +} -- cgit v1.2.3 From 622adafb2a12cac6042d4d0d7eb735b7621bf28c Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:06 -0700 Subject: selftests/bpf: Selftest for sys_connect hooks Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT attach types. Try to connect(2) to specified IP:port and test that: * remote IP:port pair is overridden; * local end of connection is bound to specified IP. All combinations of IPv4/IPv6 and TCP/UDP are tested. Example: # tcpdump -pn -i lo -w connect.pcap 2>/dev/null & [1] 478 # strace -qqf -e connect -o connect.trace ./test_sock_addr.sh Wait for testing IPv4/IPv6 to become available ... OK Load bind4 with invalid type (can pollute stderr) ... REJECTED Load bind4 with valid type ... OK Attach bind4 with invalid type ... REJECTED Attach bind4 with valid type ... OK Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r2 = 23569 1: (63) *(u32 *)(r1 +24) = r2 2: (b7) r2 = 16777343 3: (63) *(u32 *)(r1 +4) = r2 invalid bpf_context access off=4 size=4 [ 1518.404609] random: crng init done libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect4' libbpf: failed to load object './connect4_prog.o' ... REJECTED Load connect4 with valid type ... OK Attach connect4 with invalid type ... REJECTED Attach connect4 with valid type ... OK Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447) Load bind6 with invalid type (can pollute stderr) ... REJECTED Load bind6 with valid type ... OK Attach bind6 with invalid type ... REJECTED Attach bind6 with valid type ... OK Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r6 = 0 1: (63) *(u32 *)(r1 +12) = r6 invalid bpf_context access off=12 size=4 libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect6' libbpf: failed to load object './connect6_prog.o' ... REJECTED Load connect6 with valid type ... OK Attach connect6 with invalid type ... REJECTED Attach connect6 with valid type ... OK Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 37458) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 39315) ### SUCCESS # egrep 'connect\(.*AF_INET' connect.trace | \ > egrep -vw 'htons\(1025\)' | fold -b -s -w 72 502 connect(7, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(8, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 # fg tcpdump -pn -i lo -w connect.pcap 2> /dev/null # tcpdump -r connect.pcap -n tcp | cut -c 1-72 reading from file connect.pcap, link-type EN10MB (Ethernet) 17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333 17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112 17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w 17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1, 17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win 17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac 17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt 17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 12 ++- tools/lib/bpf/libbpf.c | 2 + tools/testing/selftests/bpf/Makefile | 5 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + tools/testing/selftests/bpf/connect4_prog.c | 45 +++++++++++ tools/testing/selftests/bpf/connect6_prog.c | 61 +++++++++++++++ tools/testing/selftests/bpf/test_sock_addr.c | 104 +++++++++++++++++++++++++- tools/testing/selftests/bpf/test_sock_addr.sh | 57 ++++++++++++++ 8 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/bpf/connect4_prog.c create mode 100644 tools/testing/selftests/bpf/connect6_prog.c create mode 100755 tools/testing/selftests/bpf/test_sock_addr.sh (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f2120c5c0578..71051d01e8dd 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -150,6 +150,8 @@ enum bpf_attach_type { BPF_SK_MSG_VERDICT, BPF_CGROUP_INET4_BIND, BPF_CGROUP_INET6_BIND, + BPF_CGROUP_INET4_CONNECT, + BPF_CGROUP_INET6_CONNECT, __MAX_BPF_ATTACH_TYPE }; @@ -744,6 +746,13 @@ union bpf_attr { * @flags: reserved for future use * Return: SK_PASS * + * int bpf_bind(ctx, addr, addr_len) + * Bind socket to address. Only binding to IP is supported, no port can be + * set in addr. + * @ctx: pointer to context of type bpf_sock_addr + * @addr: pointer to struct sockaddr to bind socket to + * @addr_len: length of sockaddr structure + * Return: 0 on success or negative error code */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -809,7 +818,8 @@ union bpf_attr { FN(msg_redirect_map), \ FN(msg_apply_bytes), \ FN(msg_cork_bytes), \ - FN(msg_pull_data), + FN(msg_pull_data), \ + FN(bind), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index d7ce8818982c..5922443063f0 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1887,6 +1887,8 @@ static const struct { BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), + BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), + BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), }; #undef BPF_PROG_SEC diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f4717c910874..c64d4ebc77ff 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -30,14 +30,15 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ - sockmap_tcp_msg_prog.o + sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_libbpf.sh \ test_xdp_redirect.sh \ test_xdp_meta.sh \ - test_offload.py + test_offload.py \ + test_sock_addr.sh # Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 7cae376d8d0c..d8223d99f96d 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -94,6 +94,8 @@ static int (*bpf_msg_cork_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_cork_bytes; static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = (void *) BPF_FUNC_msg_pull_data; +static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = + (void *) BPF_FUNC_bind; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions diff --git a/tools/testing/selftests/bpf/connect4_prog.c b/tools/testing/selftests/bpf/connect4_prog.c new file mode 100644 index 000000000000..5a88a681d2ab --- /dev/null +++ b/tools/testing/selftests/bpf/connect4_prog.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP4 0x7f000004U +#define DST_REWRITE_IP4 0x7f000001U +#define DST_REWRITE_PORT4 4444 + +int _version SEC("version") = 1; + +SEC("cgroup/connect4") +int connect_v4_prog(struct bpf_sock_addr *ctx) +{ + struct sockaddr_in sa; + + /* Rewrite destination. */ + ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); + ctx->user_port = bpf_htons(DST_REWRITE_PORT4); + + if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) { + ///* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = AF_INET; + sa.sin_port = bpf_htons(0); + sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/connect6_prog.c b/tools/testing/selftests/bpf/connect6_prog.c new file mode 100644 index 000000000000..8ea3f7d12dee --- /dev/null +++ b/tools/testing/selftests/bpf/connect6_prog.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP6_0 0 +#define SRC_REWRITE_IP6_1 0 +#define SRC_REWRITE_IP6_2 0 +#define SRC_REWRITE_IP6_3 6 + +#define DST_REWRITE_IP6_0 0 +#define DST_REWRITE_IP6_1 0 +#define DST_REWRITE_IP6_2 0 +#define DST_REWRITE_IP6_3 1 + +#define DST_REWRITE_PORT6 6666 + +int _version SEC("version") = 1; + +SEC("cgroup/connect6") +int connect_v6_prog(struct bpf_sock_addr *ctx) +{ + struct sockaddr_in6 sa; + + /* Rewrite destination. */ + ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); + ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); + ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); + ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); + + ctx->user_port = bpf_htons(DST_REWRITE_PORT6); + + if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) { + /* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin6_family = AF_INET6; + sa.sin6_port = bpf_htons(0); + + sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0); + sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1); + sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2); + sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index a57e13a65e37..d488f20926e8 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -12,10 +12,13 @@ #include #include +#include #include "cgroup_helpers.h" #define CG_PATH "/foo" +#define CONNECT4_PROG_PATH "./connect4_prog.o" +#define CONNECT6_PROG_PATH "./connect6_prog.o" #define SERV4_IP "192.168.1.254" #define SERV4_REWRITE_IP "127.0.0.1" @@ -254,6 +257,41 @@ static int bind6_prog_load(enum bpf_attach_type attach_type, sizeof(insns) / sizeof(struct bpf_insn), comment); } +static int connect_prog_load_path(const char *path, + enum bpf_attach_type attach_type, + const char *comment) +{ + struct bpf_prog_load_attr attr; + struct bpf_object *obj; + int prog_fd; + + memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); + attr.file = path; + attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; + attr.expected_attach_type = attach_type; + + if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) { + if (comment) + log_err(">>> Loading %s program at %s error.\n", + comment, path); + return -1; + } + + return prog_fd; +} + +static int connect4_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + return connect_prog_load_path(CONNECT4_PROG_PATH, attach_type, comment); +} + +static int connect6_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + return connect_prog_load_path(CONNECT6_PROG_PATH, attach_type, comment); +} + static void print_ip_port(int sockfd, info_fn fn, const char *fmt) { char addr_buf[INET_NTOP_BUF]; @@ -290,6 +328,11 @@ static void print_local_ip_port(int sockfd, const char *fmt) print_ip_port(sockfd, getsockname, fmt); } +static void print_remote_ip_port(int sockfd, const char *fmt) +{ + print_ip_port(sockfd, getpeername, fmt); +} + static int start_server(int type, const struct sockaddr_storage *addr, socklen_t addr_len) { @@ -324,6 +367,39 @@ out: return fd; } +static int connect_to_server(int type, const struct sockaddr_storage *addr, + socklen_t addr_len) +{ + int domain; + int fd; + + domain = addr->ss_family; + + if (domain != AF_INET && domain != AF_INET6) { + log_err("Unsupported address family"); + return -1; + } + + fd = socket(domain, type, 0); + if (fd == -1) { + log_err("Failed to creating client socket"); + return -1; + } + + if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) { + log_err("Fail to connect to server"); + goto err; + } + + print_remote_ip_port(fd, "\t Actual: connect(%s, %d)"); + print_local_ip_port(fd, " from (%s, %d)\n"); + + return 0; +err: + close(fd); + return -1; +} + static void print_test_case_num(int domain, int type) { static int test_num; @@ -356,6 +432,10 @@ static int run_test_case(int domain, int type, const char *ip, if (servfd == -1) goto err; + printf("\tRequested: connect(%s, %d) from (*, *) ..\n", ip, port); + if (connect_to_server(type, &addr, addr_len)) + goto err; + goto out; err: err = -1; @@ -380,29 +460,41 @@ static int load_and_attach_progs(int cgfd, struct program *progs, size_t i; for (i = 0; i < prog_cnt; ++i) { + printf("Load %s with invalid type (can pollute stderr) ", + progs[i].name); + fflush(stdout); progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL); if (progs[i].fd != -1) { log_err("Load with invalid type accepted for %s", progs[i].name); goto err; } + printf("... REJECTED\n"); + + printf("Load %s with valid type", progs[i].name); progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name); if (progs[i].fd == -1) { log_err("Failed to load program %s", progs[i].name); goto err; } + printf(" ... OK\n"); + + printf("Attach %s with invalid type", progs[i].name); if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type, BPF_F_ALLOW_OVERRIDE) != -1) { log_err("Attach with invalid type accepted for %s", progs[i].name); goto err; } + printf(" ... REJECTED\n"); + + printf("Attach %s with valid type", progs[i].name); if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type, BPF_F_ALLOW_OVERRIDE) == -1) { log_err("Failed to attach program %s", progs[i].name); goto err; } - printf("Attached %s program.\n", progs[i].name); + printf(" ... OK\n"); } return 0; @@ -443,12 +535,16 @@ static int run_test(void) struct program inet6_progs[] = { {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6", BPF_CGROUP_INET4_BIND}, + {BPF_CGROUP_INET6_CONNECT, connect6_prog_load, -1, "connect6", + BPF_CGROUP_INET4_CONNECT}, }; inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program); struct program inet_progs[] = { {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4", BPF_CGROUP_INET6_BIND}, + {BPF_CGROUP_INET4_CONNECT, connect4_prog_load, -1, "connect4", + BPF_CGROUP_INET6_CONNECT}, }; inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program); @@ -482,5 +578,11 @@ out: int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, + "%s has to be run via %s.sh. Skip direct run.\n", + argv[0], argv[0]); + exit(0); + } return run_test(); } diff --git a/tools/testing/selftests/bpf/test_sock_addr.sh b/tools/testing/selftests/bpf/test_sock_addr.sh new file mode 100755 index 000000000000..c6e1dcf992c4 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock_addr.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +set -eu + +ping_once() +{ + ping -q -c 1 -W 1 ${1%%/*} >/dev/null 2>&1 +} + +wait_for_ip() +{ + local _i + echo -n "Wait for testing IPv4/IPv6 to become available " + for _i in $(seq ${MAX_PING_TRIES}); do + echo -n "." + if ping_once ${TEST_IPv4} && ping_once ${TEST_IPv6}; then + echo " OK" + return + fi + done + echo 1>&2 "ERROR: Timeout waiting for test IP to become available." + exit 1 +} + +setup() +{ + # Create testing interfaces not to interfere with current environment. + ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER} + ip link set ${TEST_IF} up + ip link set ${TEST_IF_PEER} up + + ip -4 addr add ${TEST_IPv4} dev ${TEST_IF} + ip -6 addr add ${TEST_IPv6} dev ${TEST_IF} + wait_for_ip +} + +cleanup() +{ + ip link del ${TEST_IF} 2>/dev/null || : + ip link del ${TEST_IF_PEER} 2>/dev/null || : +} + +main() +{ + trap cleanup EXIT 2 3 6 15 + setup + ./test_sock_addr setup_done +} + +BASENAME=$(basename $0 .sh) +TEST_IF="${BASENAME}1" +TEST_IF_PEER="${BASENAME}2" +TEST_IPv4="127.0.0.4/8" +TEST_IPv6="::6/128" +MAX_PING_TRIES=5 + +main -- cgit v1.2.3 From 1d436885b23bf4474617914d7eb15e039c83ed99 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:08 -0700 Subject: selftests/bpf: Selftest for sys_bind post-hooks. Add selftest for attach types `BPF_CGROUP_INET4_POST_BIND` and `BPF_CGROUP_INET6_POST_BIND`. The main things tested are: * prog load behaves as expected (valid/invalid accesses in prog); * prog attach behaves as expected (load- vs attach-time attach types); * `BPF_CGROUP_INET_SOCK_CREATE` can be attached in a backward compatible way; * post-hooks return expected result and errno. Example: # ./test_sock Test case: bind4 load with invalid access: src_ip6 .. [PASS] Test case: bind4 load with invalid access: mark .. [PASS] Test case: bind6 load with invalid access: src_ip4 .. [PASS] Test case: sock_create load with invalid access: src_port .. [PASS] Test case: sock_create load w/o expected_attach_type (compat mode) .. [PASS] Test case: sock_create load w/ expected_attach_type .. [PASS] Test case: attach type mismatch bind4 vs bind6 .. [PASS] Test case: attach type mismatch bind6 vs bind4 .. [PASS] Test case: attach type mismatch default vs bind4 .. [PASS] Test case: attach type mismatch bind6 vs sock_create .. [PASS] Test case: bind4 reject all .. [PASS] Test case: bind6 reject all .. [PASS] Test case: bind6 deny specific IP & port .. [PASS] Test case: bind4 allow specific IP & port .. [PASS] Test case: bind4 allow all .. [PASS] Test case: bind6 allow all .. [PASS] Summary: 16 PASSED, 0 FAILED Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 11 + tools/testing/selftests/bpf/Makefile | 4 +- tools/testing/selftests/bpf/test_sock.c | 479 ++++++++++++++++++++++++++++++++ 3 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_sock.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 71051d01e8dd..9d07465023a2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -152,6 +152,8 @@ enum bpf_attach_type { BPF_CGROUP_INET6_BIND, BPF_CGROUP_INET4_CONNECT, BPF_CGROUP_INET6_CONNECT, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, __MAX_BPF_ATTACH_TYPE }; @@ -947,6 +949,15 @@ struct bpf_sock { __u32 protocol; __u32 mark; __u32 priority; + __u32 src_ip4; /* Allows 1,2,4-byte read. + * Stored in network byte order. + */ + __u32 src_ip6[4]; /* Allows 1,2,4-byte read. + * Stored in network byte order. + */ + __u32 src_port; /* Allows 4-byte read. + * Stored in host byte order + */ }; #define XDP_PACKET_HEADROOM 256 diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c64d4ebc77ff..0a315ddabbf4 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,8 @@ urandom_read: urandom_read.c # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log test_dev_cgroup test_tcpbpf_user test_sock_addr + test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ + test_sock test_sock_addr TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -52,6 +53,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c +$(OUTPUT)/test_sock: cgroup_helpers.c $(OUTPUT)/test_sock_addr: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c new file mode 100644 index 000000000000..73bb20cfb9b7 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include + +#include +#include +#include + +#include + +#include + +#include "cgroup_helpers.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define CG_PATH "/foo" +#define MAX_INSNS 512 + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +struct sock_test { + const char *descr; + /* BPF prog properties */ + struct bpf_insn insns[MAX_INSNS]; + enum bpf_attach_type expected_attach_type; + enum bpf_attach_type attach_type; + /* Socket properties */ + int domain; + int type; + /* Endpoint to bind() to */ + const char *ip; + unsigned short port; + /* Expected test result */ + enum { + LOAD_REJECT, + ATTACH_REJECT, + BIND_REJECT, + SUCCESS, + } result; +}; + +static struct sock_test tests[] = { + { + "bind4 load with invalid access: src_ip6", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip6[0])), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "bind4 load with invalid access: mark", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, mark)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "bind6 load with invalid access: src_ip4", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip4)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "sock_create load with invalid access: src_port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_INET_SOCK_CREATE, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "sock_create load w/o expected_attach_type (compat mode)", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + 0, + BPF_CGROUP_INET_SOCK_CREATE, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 8097, + SUCCESS, + }, + { + "sock_create load w/ expected_attach_type", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_INET_SOCK_CREATE, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 8097, + SUCCESS, + }, + { + "attach type mismatch bind4 vs bind6", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch bind6 vs bind4", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch default vs bind4", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + 0, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch bind6 vs sock_create", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET_SOCK_CREATE, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "bind4 reject all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "0.0.0.0", + 0, + BIND_REJECT, + }, + { + "bind6 reject all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::", + 0, + BIND_REJECT, + }, + { + "bind6 deny specific IP & port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (ip == expected && port == expected) */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip6[3])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x01000000, 4), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2), + + /* return DENY; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_JMP_A(1), + + /* else return ALLOW; */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::1", + 8193, + BIND_REJECT, + }, + { + "bind4 allow specific IP & port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (ip == expected && port == expected) */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x0100007F, 4), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), + + /* return ALLOW; */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + + /* else return DENY; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 4098, + SUCCESS, + }, + { + "bind4 allow all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "0.0.0.0", + 0, + SUCCESS, + }, + { + "bind6 allow all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::", + 0, + SUCCESS, + }, +}; + +static size_t probe_prog_length(const struct bpf_insn *fp) +{ + size_t len; + + for (len = MAX_INSNS - 1; len > 0; --len) + if (fp[len].code != 0 || fp[len].imm != 0) + break; + return len + 1; +} + +static int load_sock_prog(const struct bpf_insn *prog, + enum bpf_attach_type attach_type) +{ + struct bpf_load_program_attr attr; + + memset(&attr, 0, sizeof(struct bpf_load_program_attr)); + attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK; + attr.expected_attach_type = attach_type; + attr.insns = prog; + attr.insns_cnt = probe_prog_length(attr.insns); + attr.license = "GPL"; + + return bpf_load_program_xattr(&attr, bpf_log_buf, BPF_LOG_BUF_SIZE); +} + +static int attach_sock_prog(int cgfd, int progfd, + enum bpf_attach_type attach_type) +{ + return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE); +} + +static int bind_sock(int domain, int type, const char *ip, unsigned short port) +{ + struct sockaddr_storage addr; + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + int sockfd = -1; + socklen_t len; + int err = 0; + + sockfd = socket(domain, type, 0); + if (sockfd < 0) + goto err; + + memset(&addr, 0, sizeof(addr)); + + if (domain == AF_INET) { + len = sizeof(struct sockaddr_in); + addr4 = (struct sockaddr_in *)&addr; + addr4->sin_family = domain; + addr4->sin_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) + goto err; + } else if (domain == AF_INET6) { + len = sizeof(struct sockaddr_in6); + addr6 = (struct sockaddr_in6 *)&addr; + addr6->sin6_family = domain; + addr6->sin6_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) + goto err; + } else { + goto err; + } + + if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(sockfd); + return err; +} + +static int run_test_case(int cgfd, const struct sock_test *test) +{ + int progfd = -1; + int err = 0; + + printf("Test case: %s .. ", test->descr); + progfd = load_sock_prog(test->insns, test->expected_attach_type); + if (progfd < 0) { + if (test->result == LOAD_REJECT) + goto out; + else + goto err; + } + + if (attach_sock_prog(cgfd, progfd, test->attach_type) == -1) { + if (test->result == ATTACH_REJECT) + goto out; + else + goto err; + } + + if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) { + /* sys_bind() may fail for different reasons, errno has to be + * checked to confirm that BPF program rejected it. + */ + if (test->result == BIND_REJECT && errno == EPERM) + goto out; + else + goto err; + } + + + if (test->result != SUCCESS) + goto err; + + goto out; +err: + err = -1; +out: + /* Detaching w/o checking return code: best effort attempt. */ + if (progfd != -1) + bpf_prog_detach(cgfd, test->attach_type); + close(progfd); + printf("[%s]\n", err ? "FAIL" : "PASS"); + return err; +} + +static int run_tests(int cgfd) +{ + int passes = 0; + int fails = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + if (run_test_case(cgfd, &tests[i])) + ++fails; + else + ++passes; + } + printf("Summary: %d PASSED, %d FAILED\n", passes, fails); + return fails ? -1 : 0; +} + +int main(int argc, char **argv) +{ + int cgfd = -1; + int err = 0; + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CG_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CG_PATH)) + goto err; + + if (run_tests(cgfd)) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + return err; +} -- cgit v1.2.3