| #!/bin/bash | 
 | # SPDX-License-Identifier: GPL-2.0 | 
 |  | 
 | # This test is for checking GRE GSO. | 
 |  | 
 | ret=0 | 
 | # Kselftest framework requirement - SKIP code is 4. | 
 | ksft_skip=4 | 
 |  | 
 | # all tests in this script. Can be overridden with -t option | 
 | TESTS="gre_gso" | 
 |  | 
 | VERBOSE=0 | 
 | PAUSE_ON_FAIL=no | 
 | PAUSE=no | 
 | IP="ip -netns ns1" | 
 | NS_EXEC="ip netns exec ns1" | 
 | TMPFILE=`mktemp` | 
 | PID= | 
 |  | 
 | log_test() | 
 | { | 
 | 	local rc=$1 | 
 | 	local expected=$2 | 
 | 	local msg="$3" | 
 |  | 
 | 	if [ ${rc} -eq ${expected} ]; then | 
 | 		printf "    TEST: %-60s  [ OK ]\n" "${msg}" | 
 | 		nsuccess=$((nsuccess+1)) | 
 | 	else | 
 | 		ret=1 | 
 | 		nfail=$((nfail+1)) | 
 | 		printf "    TEST: %-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 | 
 |  | 
 | 	if [ "${PAUSE}" = "yes" ]; then | 
 | 		echo | 
 | 		echo "hit enter to continue, 'q' to quit" | 
 | 		read a | 
 | 		[ "$a" = "q" ] && exit 1 | 
 | 	fi | 
 | } | 
 |  | 
 | setup() | 
 | { | 
 | 	set -e | 
 | 	ip netns add ns1 | 
 | 	ip netns set ns1 auto | 
 | 	$IP link set dev lo up | 
 |  | 
 | 	ip link add veth0 type veth peer name veth1 | 
 | 	ip link set veth0 up | 
 | 	ip link set veth1 netns ns1 | 
 | 	$IP link set veth1 name veth0 | 
 | 	$IP link set veth0 up | 
 |  | 
 | 	dd if=/dev/urandom of=$TMPFILE bs=1024 count=2048 &>/dev/null | 
 | 	set +e | 
 | } | 
 |  | 
 | cleanup() | 
 | { | 
 | 	rm -rf $TMPFILE | 
 | 	[ -n "$PID" ] && kill $PID | 
 | 	ip link del dev gre1 &> /dev/null | 
 | 	ip link del dev veth0 &> /dev/null | 
 | 	ip netns del ns1 | 
 | } | 
 |  | 
 | get_linklocal() | 
 | { | 
 | 	local dev=$1 | 
 | 	local ns=$2 | 
 | 	local addr | 
 |  | 
 | 	[ -n "$ns" ] && ns="-netns $ns" | 
 |  | 
 | 	addr=$(ip -6 -br $ns 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 | 
 | } | 
 |  | 
 | gre_create_tun() | 
 | { | 
 | 	local a1=$1 | 
 | 	local a2=$2 | 
 | 	local mode | 
 |  | 
 | 	[[ $a1 =~ ^[0-9.]*$ ]] && mode=gre || mode=ip6gre | 
 |  | 
 | 	ip tunnel add gre1 mode $mode local $a1 remote $a2 dev veth0 | 
 | 	ip link set gre1 up | 
 | 	$IP tunnel add gre1 mode $mode local $a2 remote $a1 dev veth0 | 
 | 	$IP link set gre1 up | 
 | } | 
 |  | 
 | gre_gst_test_checks() | 
 | { | 
 | 	local name=$1 | 
 | 	local addr=$2 | 
 | 	local proto=$3 | 
 |  | 
 | 	[ "$proto" == 6 ] && addr="[$addr]" | 
 |  | 
 | 	$NS_EXEC socat - tcp${proto}-listen:$port,reuseaddr,fork >/dev/null & | 
 | 	PID=$! | 
 | 	while ! $NS_EXEC ss -ltn | grep -q $port; do ((i++)); sleep 0.01; done | 
 |  | 
 | 	cat $TMPFILE | timeout 1 socat -u STDIN TCP:$addr:$port | 
 | 	log_test $? 0 "$name - copy file w/ TSO" | 
 |  | 
 | 	ethtool -K veth0 tso off | 
 |  | 
 | 	cat $TMPFILE | timeout 1 socat -u STDIN TCP:$addr:$port | 
 | 	log_test $? 0 "$name - copy file w/ GSO" | 
 |  | 
 | 	ethtool -K veth0 tso on | 
 |  | 
 | 	kill $PID | 
 | 	PID= | 
 | } | 
 |  | 
 | gre6_gso_test() | 
 | { | 
 | 	local port=7777 | 
 |  | 
 | 	setup | 
 |  | 
 | 	a1=$(get_linklocal veth0) | 
 | 	a2=$(get_linklocal veth0 ns1) | 
 |  | 
 | 	gre_create_tun $a1 $a2 | 
 |  | 
 | 	ip  addr add 172.16.2.1/24 dev gre1 | 
 | 	$IP addr add 172.16.2.2/24 dev gre1 | 
 |  | 
 | 	ip  -6 addr add 2001:db8:1::1/64 dev gre1 nodad | 
 | 	$IP -6 addr add 2001:db8:1::2/64 dev gre1 nodad | 
 |  | 
 | 	sleep 2 | 
 |  | 
 | 	gre_gst_test_checks GREv6/v4 172.16.2.2 4 | 
 | 	gre_gst_test_checks GREv6/v6 2001:db8:1::2 6 | 
 |  | 
 | 	cleanup | 
 | } | 
 |  | 
 | gre_gso_test() | 
 | { | 
 | 	gre6_gso_test | 
 | } | 
 |  | 
 | ################################################################################ | 
 | # usage | 
 |  | 
 | usage() | 
 | { | 
 | 	cat <<EOF | 
 | usage: ${0##*/} OPTS | 
 |  | 
 |         -t <test>   Test(s) to run (default: all) | 
 |                     (options: $TESTS) | 
 |         -p          Pause on fail | 
 |         -P          Pause after each test before cleanup | 
 |         -v          verbose mode (show commands and output) | 
 | EOF | 
 | } | 
 |  | 
 | ################################################################################ | 
 | # main | 
 |  | 
 | while getopts :t:pPhv o | 
 | do | 
 | 	case $o in | 
 | 		t) TESTS=$OPTARG;; | 
 | 		p) PAUSE_ON_FAIL=yes;; | 
 | 		P) PAUSE=yes;; | 
 | 		v) VERBOSE=$(($VERBOSE + 1));; | 
 | 		h) usage; exit 0;; | 
 | 		*) usage; exit 1;; | 
 | 	esac | 
 | done | 
 |  | 
 | PEER_CMD="ip netns exec ${PEER_NS}" | 
 |  | 
 | # make sure we don't pause twice | 
 | [ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no | 
 |  | 
 | if [ "$(id -u)" -ne 0 ];then | 
 | 	echo "SKIP: Need root privileges" | 
 | 	exit $ksft_skip; | 
 | fi | 
 |  | 
 | if [ ! -x "$(command -v ip)" ]; then | 
 | 	echo "SKIP: Could not run test without ip tool" | 
 | 	exit $ksft_skip | 
 | fi | 
 |  | 
 | if [ ! -x "$(command -v socat)" ]; then | 
 | 	echo "SKIP: Could not run test without socat tool" | 
 | 	exit $ksft_skip | 
 | fi | 
 |  | 
 | # start clean | 
 | cleanup &> /dev/null | 
 |  | 
 | for t in $TESTS | 
 | do | 
 | 	case $t in | 
 | 	gre_gso)		gre_gso_test;; | 
 |  | 
 | 	help) echo "Test names: $TESTS"; exit 0;; | 
 | 	esac | 
 | done | 
 |  | 
 | if [ "$TESTS" != "none" ]; then | 
 | 	printf "\nTests passed: %3d\n" ${nsuccess} | 
 | 	printf "Tests failed: %3d\n"   ${nfail} | 
 | fi | 
 |  | 
 | exit $ret |