1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Run a series of udpgro functional tests. 5*4882a593Smuzhiyun 6*4882a593Smuzhiyunreadonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)" 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun# set global exit status, but never reset nonzero one. 9*4882a593Smuzhiyuncheck_err() 10*4882a593Smuzhiyun{ 11*4882a593Smuzhiyun if [ $ret -eq 0 ]; then 12*4882a593Smuzhiyun ret=$1 13*4882a593Smuzhiyun fi 14*4882a593Smuzhiyun} 15*4882a593Smuzhiyun 16*4882a593Smuzhiyuncleanup() { 17*4882a593Smuzhiyun local -r jobs="$(jobs -p)" 18*4882a593Smuzhiyun local -r ns="$(ip netns list|grep $PEER_NS)" 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun [ -n "${jobs}" ] && kill -1 ${jobs} 2>/dev/null 21*4882a593Smuzhiyun [ -n "$ns" ] && ip netns del $ns 2>/dev/null 22*4882a593Smuzhiyun} 23*4882a593Smuzhiyuntrap cleanup EXIT 24*4882a593Smuzhiyun 25*4882a593Smuzhiyuncfg_veth() { 26*4882a593Smuzhiyun ip netns add "${PEER_NS}" 27*4882a593Smuzhiyun ip -netns "${PEER_NS}" link set lo up 28*4882a593Smuzhiyun ip link add type veth 29*4882a593Smuzhiyun ip link set dev veth0 up 30*4882a593Smuzhiyun ip addr add dev veth0 192.168.1.2/24 31*4882a593Smuzhiyun ip addr add dev veth0 2001:db8::2/64 nodad 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun ip link set dev veth1 netns "${PEER_NS}" 34*4882a593Smuzhiyun ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24 35*4882a593Smuzhiyun ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad 36*4882a593Smuzhiyun ip -netns "${PEER_NS}" link set dev veth1 up 37*4882a593Smuzhiyun ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy 38*4882a593Smuzhiyun} 39*4882a593Smuzhiyun 40*4882a593Smuzhiyunrun_one() { 41*4882a593Smuzhiyun # use 'rx' as separator between sender args and receiver args 42*4882a593Smuzhiyun local -r all="$@" 43*4882a593Smuzhiyun local -r tx_args=${all%rx*} 44*4882a593Smuzhiyun local -r rx_args=${all#*rx} 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun cfg_veth 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} && \ 49*4882a593Smuzhiyun echo "ok" || \ 50*4882a593Smuzhiyun echo "failed" & 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun # Hack: let bg programs complete the startup 53*4882a593Smuzhiyun sleep 0.1 54*4882a593Smuzhiyun ./udpgso_bench_tx ${tx_args} 55*4882a593Smuzhiyun ret=$? 56*4882a593Smuzhiyun wait $(jobs -p) 57*4882a593Smuzhiyun return $ret 58*4882a593Smuzhiyun} 59*4882a593Smuzhiyun 60*4882a593Smuzhiyunrun_test() { 61*4882a593Smuzhiyun local -r args=$@ 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun printf " %-40s" "$1" 64*4882a593Smuzhiyun ./in_netns.sh $0 __subprocess $2 rx -G -r $3 65*4882a593Smuzhiyun} 66*4882a593Smuzhiyun 67*4882a593Smuzhiyunrun_one_nat() { 68*4882a593Smuzhiyun # use 'rx' as separator between sender args and receiver args 69*4882a593Smuzhiyun local addr1 addr2 pid family="" ipt_cmd=ip6tables 70*4882a593Smuzhiyun local -r all="$@" 71*4882a593Smuzhiyun local -r tx_args=${all%rx*} 72*4882a593Smuzhiyun local -r rx_args=${all#*rx} 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun if [[ ${tx_args} = *-4* ]]; then 75*4882a593Smuzhiyun ipt_cmd=iptables 76*4882a593Smuzhiyun family=-4 77*4882a593Smuzhiyun addr1=192.168.1.1 78*4882a593Smuzhiyun addr2=192.168.1.3/24 79*4882a593Smuzhiyun else 80*4882a593Smuzhiyun addr1=2001:db8::1 81*4882a593Smuzhiyun addr2="2001:db8::3/64 nodad" 82*4882a593Smuzhiyun fi 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun cfg_veth 85*4882a593Smuzhiyun ip -netns "${PEER_NS}" addr add dev veth1 ${addr2} 86*4882a593Smuzhiyun 87*4882a593Smuzhiyun # fool the GRO engine changing the destination address ... 88*4882a593Smuzhiyun ip netns exec "${PEER_NS}" $ipt_cmd -t nat -I PREROUTING -d ${addr1} -j DNAT --to-destination ${addr2%/*} 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun # ... so that GRO will match the UDP_GRO enabled socket, but packets 91*4882a593Smuzhiyun # will land on the 'plain' one 92*4882a593Smuzhiyun ip netns exec "${PEER_NS}" ./udpgso_bench_rx -G ${family} -b ${addr1} -n 0 & 93*4882a593Smuzhiyun pid=$! 94*4882a593Smuzhiyun ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${family} -b ${addr2%/*} ${rx_args} && \ 95*4882a593Smuzhiyun echo "ok" || \ 96*4882a593Smuzhiyun echo "failed"& 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun sleep 0.1 99*4882a593Smuzhiyun ./udpgso_bench_tx ${tx_args} 100*4882a593Smuzhiyun ret=$? 101*4882a593Smuzhiyun kill -INT $pid 102*4882a593Smuzhiyun wait $(jobs -p) 103*4882a593Smuzhiyun return $ret 104*4882a593Smuzhiyun} 105*4882a593Smuzhiyun 106*4882a593Smuzhiyunrun_one_2sock() { 107*4882a593Smuzhiyun # use 'rx' as separator between sender args and receiver args 108*4882a593Smuzhiyun local -r all="$@" 109*4882a593Smuzhiyun local -r tx_args=${all%rx*} 110*4882a593Smuzhiyun local -r rx_args=${all#*rx} 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun cfg_veth 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} -p 12345 & 115*4882a593Smuzhiyun ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 2000 -R 10 ${rx_args} && \ 116*4882a593Smuzhiyun echo "ok" || \ 117*4882a593Smuzhiyun echo "failed" & 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun # Hack: let bg programs complete the startup 120*4882a593Smuzhiyun sleep 0.1 121*4882a593Smuzhiyun ./udpgso_bench_tx ${tx_args} -p 12345 122*4882a593Smuzhiyun sleep 0.1 123*4882a593Smuzhiyun # first UDP GSO socket should be closed at this point 124*4882a593Smuzhiyun ./udpgso_bench_tx ${tx_args} 125*4882a593Smuzhiyun ret=$? 126*4882a593Smuzhiyun wait $(jobs -p) 127*4882a593Smuzhiyun return $ret 128*4882a593Smuzhiyun} 129*4882a593Smuzhiyun 130*4882a593Smuzhiyunrun_nat_test() { 131*4882a593Smuzhiyun local -r args=$@ 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun printf " %-40s" "$1" 134*4882a593Smuzhiyun ./in_netns.sh $0 __subprocess_nat $2 rx -r $3 135*4882a593Smuzhiyun} 136*4882a593Smuzhiyun 137*4882a593Smuzhiyunrun_2sock_test() { 138*4882a593Smuzhiyun local -r args=$@ 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun printf " %-40s" "$1" 141*4882a593Smuzhiyun ./in_netns.sh $0 __subprocess_2sock $2 rx -G -r $3 142*4882a593Smuzhiyun} 143*4882a593Smuzhiyun 144*4882a593Smuzhiyunrun_all() { 145*4882a593Smuzhiyun local -r core_args="-l 4" 146*4882a593Smuzhiyun local -r ipv4_args="${core_args} -4 -D 192.168.1.1" 147*4882a593Smuzhiyun local -r ipv6_args="${core_args} -6 -D 2001:db8::1" 148*4882a593Smuzhiyun ret=0 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun echo "ipv4" 151*4882a593Smuzhiyun run_test "no GRO" "${ipv4_args} -M 10 -s 1400" "-4 -n 10 -l 1400" 152*4882a593Smuzhiyun check_err $? 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun # explicitly check we are not receiving UDP_SEGMENT cmsg (-S -1) 155*4882a593Smuzhiyun # when GRO does not take place 156*4882a593Smuzhiyun run_test "no GRO chk cmsg" "${ipv4_args} -M 10 -s 1400" "-4 -n 10 -l 1400 -S -1" 157*4882a593Smuzhiyun check_err $? 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun # the GSO packets are aggregated because: 160*4882a593Smuzhiyun # * veth schedule napi after each xmit 161*4882a593Smuzhiyun # * segmentation happens in BH context, veth napi poll is delayed after 162*4882a593Smuzhiyun # the transmission of the last segment 163*4882a593Smuzhiyun run_test "GRO" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720" 164*4882a593Smuzhiyun check_err $? 165*4882a593Smuzhiyun run_test "GRO chk cmsg" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720 -S 1472" 166*4882a593Smuzhiyun check_err $? 167*4882a593Smuzhiyun run_test "GRO with custom segment size" "${ipv4_args} -M 1 -s 14720 -S 500 " "-4 -n 1 -l 14720" 168*4882a593Smuzhiyun check_err $? 169*4882a593Smuzhiyun run_test "GRO with custom segment size cmsg" "${ipv4_args} -M 1 -s 14720 -S 500 " "-4 -n 1 -l 14720 -S 500" 170*4882a593Smuzhiyun check_err $? 171*4882a593Smuzhiyun 172*4882a593Smuzhiyun run_nat_test "bad GRO lookup" "${ipv4_args} -M 1 -s 14720 -S 0" "-n 10 -l 1472" 173*4882a593Smuzhiyun check_err $? 174*4882a593Smuzhiyun run_2sock_test "multiple GRO socks" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720 -S 1472" 175*4882a593Smuzhiyun check_err $? 176*4882a593Smuzhiyun 177*4882a593Smuzhiyun echo "ipv6" 178*4882a593Smuzhiyun run_test "no GRO" "${ipv6_args} -M 10 -s 1400" "-n 10 -l 1400" 179*4882a593Smuzhiyun check_err $? 180*4882a593Smuzhiyun run_test "no GRO chk cmsg" "${ipv6_args} -M 10 -s 1400" "-n 10 -l 1400 -S -1" 181*4882a593Smuzhiyun check_err $? 182*4882a593Smuzhiyun run_test "GRO" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 1 -l 14520" 183*4882a593Smuzhiyun check_err $? 184*4882a593Smuzhiyun run_test "GRO chk cmsg" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 1 -l 14520 -S 1452" 185*4882a593Smuzhiyun check_err $? 186*4882a593Smuzhiyun run_test "GRO with custom segment size" "${ipv6_args} -M 1 -s 14520 -S 500" "-n 1 -l 14520" 187*4882a593Smuzhiyun check_err $? 188*4882a593Smuzhiyun run_test "GRO with custom segment size cmsg" "${ipv6_args} -M 1 -s 14520 -S 500" "-n 1 -l 14520 -S 500" 189*4882a593Smuzhiyun check_err $? 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun run_nat_test "bad GRO lookup" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 10 -l 1452" 192*4882a593Smuzhiyun check_err $? 193*4882a593Smuzhiyun run_2sock_test "multiple GRO socks" "${ipv6_args} -M 1 -s 14520 -S 0 " "-n 1 -l 14520 -S 1452" 194*4882a593Smuzhiyun check_err $? 195*4882a593Smuzhiyun return $ret 196*4882a593Smuzhiyun} 197*4882a593Smuzhiyun 198*4882a593Smuzhiyunif [ ! -f ../bpf/xdp_dummy.o ]; then 199*4882a593Smuzhiyun echo "Missing xdp_dummy helper. Build bpf selftest first" 200*4882a593Smuzhiyun exit -1 201*4882a593Smuzhiyunfi 202*4882a593Smuzhiyun 203*4882a593Smuzhiyunif [[ $# -eq 0 ]]; then 204*4882a593Smuzhiyun run_all 205*4882a593Smuzhiyunelif [[ $1 == "__subprocess" ]]; then 206*4882a593Smuzhiyun shift 207*4882a593Smuzhiyun run_one $@ 208*4882a593Smuzhiyunelif [[ $1 == "__subprocess_nat" ]]; then 209*4882a593Smuzhiyun shift 210*4882a593Smuzhiyun run_one_nat $@ 211*4882a593Smuzhiyunelif [[ $1 == "__subprocess_2sock" ]]; then 212*4882a593Smuzhiyun shift 213*4882a593Smuzhiyun run_one_2sock $@ 214*4882a593Smuzhiyunfi 215*4882a593Smuzhiyun 216*4882a593Smuzhiyunexit $? 217