1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4source lib.sh 5 6# shellcheck disable=SC2155 # prefer RO variable over return value from cmd 7readonly CLI="$(dirname "$(readlink -f "$0")")/../../../net/ynl/pyynl/cli.py" 8 9readonly SRC=1 10readonly DST=2 11 12readonly NET_V4=192.168.1. 13readonly NET_V6=2001:db8:: 14readonly OL1_NET_V4=172.16.1. 15readonly OL1_NET_V6=2001:db8:1:: 16readonly OL2_NET_V4=172.16.2. 17readonly OL2_NET_V6=2001:db8:2:: 18 19trap cleanup_all_ns EXIT 20 21# shellcheck disable=SC2329 # can't figure out usage trough a variable 22is_ipv6() { 23 if [[ $1 =~ .*:.* ]]; then 24 return 0 25 fi 26 return 1 27} 28 29# shellcheck disable=SC2329 # can't figure out usage trough a variable 30create_gnv_endpoint() { 31 local -r netns=$1 32 local -r bm_rem_addr=$2 33 local -r gnv_dev=$3 34 local -r gnv_id=$4 35 local opts=$5 36 local gnv_json 37 local rem 38 39 if is_ipv6 "$bm_rem_addr"; then 40 rem=remote6 41 else 42 rem=remote 43 fi 44 45 # add ynl opt separator, if needed 46 [ -n "$opts" ] && opts=", $opts" 47 48 gnv_json="{ \"id\": $gnv_id, \"$rem\": \"$bm_rem_addr\"$opts }" 49 ip netns exec "$netns" "$CLI" --family rt-link --create --excl \ 50 --do newlink --json "{\"ifname\": \"$gnv_dev\", 51 \"linkinfo\": {\"kind\":\"geneve\", 52 \"data\": $gnv_json } }" > /dev/null 53 ip -n "$netns" link set dev "$gnv_dev" up 54} 55 56# shellcheck disable=SC2329 # can't figure out usage trough a variable 57create_vxlan_endpoint() { 58 local -r netns=$1 59 local -r bm_rem_addr=$2 60 local -r vxlan_dev=$3 61 local -r vxlan_id=$4 62 local -r opts_str=$5 63 local oldifs 64 local -a opts 65 local opt 66 67 # convert the arguments from yaml format 68 oldifs=$IFS 69 IFS=',' 70 for opt in $opts_str; do 71 local pattern='"port":' 72 73 [ -n "$opt" ] || continue 74 75 opts+=("${opt/$pattern*/dstport}" "${opt/$pattern/}") 76 done 77 IFS=$oldifs 78 [ ${#opts[@]} -gt 0 ] || opts+=("dstport" "4789") 79 80 ip -n "$netns" link add "$vxlan_dev" type vxlan id "$vxlan_id" \ 81 remote "$bm_rem_addr" "${opts[@]}" 82 ip -n "$netns" link set dev "$vxlan_dev" up 83} 84 85create_ns() { 86 local nested_opt='"port":6082' 87 local create_endpoint 88 local options="$1" 89 local feature 90 local dev 91 local id 92 local ns 93 94 RET=0 95 96 # +-------------+ +-------------+ 97 # | NS_SRC | | NS_NST_DST | 98 # | | | | 99 # | gnv_nst1 | | gnv_nst2 | 100 # | + | | + | 101 # | | | | | | 102 # | + | | + | 103 # | gnv1 | | gnv2 | 104 # | + | | + | 105 # | | | | | | 106 # | + veth1 +--------+ veth2 + | 107 # | | | | 108 # +-------------+ +-------------+ 109 110 setup_ns NS_SRC NS_DST 111 112 # concatenate caller provided options and default one 113 [ -n "$2" ] && nested_opt="$nested_opt,$2" 114 115 ip link add name "veth$SRC" netns "$NS_SRC" type veth \ 116 peer name "veth$DST" netns "$NS_DST" 117 case "$ENCAP" in 118 vxlan) 119 create_endpoint=create_vxlan_endpoint 120 dev=vx 121 ;; 122 geneve) 123 create_endpoint=create_gnv_endpoint 124 dev=gnv 125 ;; 126 esac 127 128 id=1 129 for ns in "${NS_LIST[@]}"; do 130 ip -n "$ns" link set dev "veth$id" up 131 132 # ensure the sender can do large write just after 3whs 133 ip netns exec "$ns" \ 134 sysctl -qw net.ipv4.tcp_wmem="4096 4194304 4194304" 135 136 # note that 3 - $SRC == $DST and 3 - $DST == $SRC 137 if [ $FAMILY = "4" ]; then 138 ip -n "$ns" addr add dev "veth$id" "$NET_V4$id/24" 139 $create_endpoint "$ns" "$NET_V4$((3 - id))" \ 140 "$dev$id" 4 "$options" 141 ip -n "$ns" addr add dev "$dev$id" "$OL1_NET_V4$id/24" 142 143 # nested tunnel devices 144 # pmtu can't be propagated to upper layer devices; 145 # need manual adjust 146 $create_endpoint "$ns" "$OL1_NET_V4$((3 - id))" \ 147 "$dev"_nst"$id" 40 "$nested_opt" 148 ip -n "$ns" addr add dev "$dev"_nst"$id" \ 149 "$OL2_NET_V4$id/24" 150 ip -n "$ns" link set dev "$dev"_nst"$id" mtu 1392 151 else 152 ip -n "$ns" addr add dev "veth$id" "$NET_V6$id/64" \ 153 nodad 154 $create_endpoint "$ns" "$NET_V6$((3 - id))" \ 155 "$dev"6"$id" 6 "$options" 156 ip -n "$ns" addr add dev "$dev"6"$id" \ 157 "$OL1_NET_V6$id/64" nodad 158 159 $create_endpoint "$ns" "$OL1_NET_V6$((3 - id))" \ 160 "$dev"6_nst"$id" 60 "$nested_opt" 161 ip -n "$ns" addr add dev "$dev"6_nst"$id" \ 162 "$OL2_NET_V6$id/64" nodad 163 ip -n "$ns" link set dev "$dev"6_nst"$id" mtu 1352 164 fi 165 id=$((id+1)) 166 done 167 168 # enable GRO heuristic on the veth peer and ensure UDP L4 over tunnel is 169 # actually segmented 170 for feature in tso tx-udp_tnl-segmentation; do 171 ip netns exec "$NS_SRC" ethtool -K "veth$SRC" \ 172 "$feature" off 2>/dev/null 173 done 174} 175 176create_ns_gso() { 177 local dev 178 179 create_ns "$@" 180 if [ "$ENCAP" = "geneve" ]; then 181 dev=gnv 182 else 183 dev=vx 184 fi 185 [ "$FAMILY" = "6" ] && dev="$dev"6 186 ip netns exec "$NS_SRC" ethtool -K "$dev$SRC" \ 187 tx-gso-partial on \ 188 tx-udp_tnl-segmentation on \ 189 tx-udp_tnl-csum-segmentation on 190} 191 192create_ns_gso_gro() { 193 create_ns_gso "$@" 194 ip netns exec "$NS_DST" ethtool -K "veth$DST" gro on 195 ip netns exec "$NS_SRC" ethtool -K "veth$SRC" tx off >/dev/null 2>&1 196} 197 198run_test() { 199 local -r dst=$NET$DST 200 local -r msg=$1 201 local -r total_size=$2 202 local -r encappkts=$3 203 local inner_proto_offset=0 204 local inner_maclen=14 205 local rx_family="-4" 206 local ipt=iptables 207 local bpf_filter 208 local -a rx_args 209 local wire_pkts 210 local rcvpkts 211 local encl=8 212 local dport 213 local pkts 214 local snd 215 216 if [ $FAMILY = "6" ]; then 217 ipt=ip6tables 218 else 219 # rx program does not support '-6' and implies ipv6 usage by 220 # default 221 rx_args=("$rx_family") 222 fi 223 224 # The received can only check fixed size packet 225 pkts=$((total_size / GSO_SIZE)) 226 if [ -n "$4" ]; then 227 wire_pkts=$4 228 elif [ $((total_size % GSO_SIZE)) -eq 0 ]; then 229 wire_pkts=1 230 rx_args+=("-l" "$GSO_SIZE") 231 else 232 wire_pkts=2 233 pkts=$((pkts + 1)) 234 fi 235 236 if [ "$ENCAP" = "geneve" ]; then 237 dport=6081 238 else 239 dport=4789 240 fi 241 242 # Either: 243 # - IPv4, nested tunnel carries UDP over IPv4, with dport 6082, 244 # innermost is TCP over IPv4 on port 8000 245 # - IPv6, nested tunnel carries UDP over IPv6, with dport 6082, 246 # innermost is TCP over IPv6 on port 8000 247 # The nested tunnel port is 6082 and the nested encap len is 8 248 # regardless of the encap type (no geneve opts). 249 # In inherit protocol mode there is no nested mac hdr and the nested 250 # l3 protocol type field belongs to the geneve hdr. 251 [ "$USE_HINT" = true ] && encl=16 252 [ "$INHERIT" = true ] && inner_maclen=0 253 [ "$INHERIT" = true ] && inner_proto_offset=-4 254 local inner=$((inner_maclen+encl)) 255 local proto=$((inner_maclen+encl+inner_proto_offset)) 256 bpf_filter=$(nfbpf_compile "(ip && 257 ip[$((40+encl))] == 0x08 && ip[$((41+encl))] == 0x00 && 258 ip[$((51+encl))] == 0x11 && 259 ip[$((64+encl))] == 0x17 && ip[$((65+encl))] == 0xc2 && 260 ip[$((76+proto))] == 0x08 && ip[$((77+proto))] == 0x00 && 261 ip[$((87+inner))] == 0x6 && 262 ip[$((100+inner))] == 0x1f && ip[$((101+inner))] == 0x40) || 263 (ip6 && 264 ip6[$((60+encl))] == 0x86 && ip6[$((61+encl))] == 0xdd && 265 ip6[$((68+encl))] == 0x11 && 266 ip6[$((104+encl))] == 0x17 && ip6[$((105+encl))] == 0xc2 && 267 ip6[$((116+proto))] == 0x86 && ip6[$((117+proto))] == 0xdd && 268 ip6[$((124+inner))] == 0x6 && 269 ip6[$((160+inner))] == 0x1f && ip6[$((161+inner))] == 0x40)") 270 271 # ignore shorts packet, to avoid arp/mld induced noise 272 ip netns exec "$NS_SRC" "$ipt" -A OUTPUT -p udp --dport "$dport" \ 273 -m length --length 600:65535 -m bpf --bytecode "$bpf_filter" 274 ip netns exec "$NS_DST" "$ipt" -A INPUT -p udp --dport "$dport" \ 275 -m length --length 600:65535 -m bpf --bytecode "$bpf_filter" 276 ip netns exec "$NS_DST" ./udpgso_bench_rx -C 2000 -t -R 100 \ 277 -n "$pkts" "${rx_args[@]}" & 278 local pid=$! 279 wait_local_port_listen "$NS_DST" 8000 tcp 280 ip netns exec "$NS_SRC" ./udpgso_bench_tx -"$FAMILY" -t -M 1 \ 281 -s "$total_size" -D "$dst" 282 local ret=$? 283 check_err "$ret" "client failure exit code $ret" 284 wait "$pid" 285 ret=$? 286 check_err "$ret" "sever failure exit code $ret" 287 288 snd=$(ip netns exec "$NS_SRC" "$ipt"-save -c | 289 grep "dport $dport" | sed -e 's/\[//' -e 's/:.*//') 290 291 [ "$snd" = "$wire_pkts" ] 292 # shellcheck disable=SC2319 # known false positive 293 check_err $? "send $snd packets on the lowest link, expected $wire_pkts" 294 295 rcvpkts=$(ip netns exec "$NS_DST" "$ipt"-save -c | \ 296 grep "dport $dport" | sed -e 's/\[//' -e 's/:.*//') 297 298 [ "$rcvpkts" = "$encappkts" ] 299 check_err $? "received $rcvpkts $ENCAP packets, expected $encappkts" 300 log_test "$msg" 301} 302 303run_tests() { 304 for FAMILY in 4 6; do 305 NET=$OL2_NET_V4 306 GSO_SIZE=1340 # 1392 - 20 - 32 307 308 if [ $FAMILY = 6 ]; then 309 NET=$OL2_NET_V6 310 GSO_SIZE=1280 # 1352 - 40 - 32 311 fi 312 313 echo "IPv$FAMILY" 314 315 unset USE_HINT 316 unset INHERIT 317 318 # "geneve" must be last encap in list, so that later 319 # test cases will run on it 320 for ENCAP in "vxlan" "geneve"; do 321 create_ns 322 run_test "No GSO - $ENCAP" $((GSO_SIZE * 4)) 4 4 323 cleanup_all_ns 324 325 create_ns_gso 326 run_test "GSO without GRO - $ENCAP" $((GSO_SIZE * 4)) \ 327 4 1 328 cleanup_all_ns 329 330 # IPv4 only test 331 [ $FAMILY = "4" ] || continue 332 create_ns_gso 333 ip netns exec "$NS_SRC" \ 334 sysctl -qw net.ipv4.ip_no_pmtu_disc=1 335 run_test "GSO disable due to no fixedid - $ENCAP" \ 336 $((GSO_SIZE * 4)) 4 4 337 cleanup_all_ns 338 done 339 340 # GRO tests imply/require geneve encap, the only one providing 341 # GRO hints 342 create_ns_gso_gro 343 run_test "double tunnel GRO, no hints" $((GSO_SIZE * 4)) 4 344 cleanup_all_ns 345 346 # hint option is expected for all the following tests in the RX 347 # path 348 USE_HINT=true 349 create_ns_gso_gro \ 350 '"gro-hint":1,"udp-zero-csum6-tx":1,"udp-zero-csum6-rx":1' \ 351 '"udp-zero-csum6-tx":1,"udp-zero-csum6-rx":1' 352 run_test "double tunnel GRO" $((GSO_SIZE * 4)) 1 353 cleanup_all_ns 354 355 create_ns_gso_gro '"gro-hint":1,"udp-csum":1' '"udp-csum":1' 356 run_test "double tunnel GRO - csum complete" $((GSO_SIZE * 4))\ 357 1 358 cleanup_all_ns 359 360 create_ns_gso_gro '"gro-hint":1' \ 361 '"udp-csum":0,"udp-zero-csum6-tx":1,"udp-zero-csum6-rx":1' 362 run_test "double tunnel GRO - no nested csum" \ 363 $((GSO_SIZE * 4)) 1 364 cleanup_all_ns 365 366 create_ns_gso_gro \ 367 '"gro-hint":1,"udp-zero-csum6-tx":1,"udp-zero-csum6-rx":1' \ 368 '"udp-csum":1' 369 run_test "double tunnel GRO - nested csum, outer 0-csum, skip"\ 370 $((GSO_SIZE * 4)) 4 371 cleanup_all_ns 372 373 INHERIT=true 374 create_ns_gso_gro '"gro-hint":1,"udp-csum":1' \ 375 '"udp-csum":1,"inner-proto-inherit":1' 376 run_test "double tunnel GRO - nested inherit proto" \ 377 $((GSO_SIZE * 4)) 1 378 cleanup_all_ns 379 unset INHERIT 380 381 create_ns_gso_gro '"gro-hint":1' 382 run_test "double tunnel GRO - short last pkt" \ 383 $((GSO_SIZE * 4 + GSO_SIZE / 2)) 2 384 cleanup_all_ns 385 done 386} 387 388require_command nfbpf_compile 389require_command jq 390 391# tcp retransmisions will break the accounting 392xfail_on_slow run_tests 393exit "$EXIT_STATUS" 394