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