1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4############################################################################## 5# Defines 6 7: "${WAIT_TIMEOUT:=20}" 8 9BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms 10 11# Kselftest framework constants. 12ksft_pass=0 13ksft_fail=1 14ksft_xfail=2 15ksft_skip=4 16 17# namespace list created by setup_ns 18NS_LIST=() 19 20############################################################################## 21# Helpers 22 23__ksft_status_merge() 24{ 25 local a=$1; shift 26 local b=$1; shift 27 local -A weights 28 local weight=0 29 30 local i 31 for i in "$@"; do 32 weights[$i]=$((weight++)) 33 done 34 35 if [[ ${weights[$a]} > ${weights[$b]} ]]; then 36 echo "$a" 37 return 0 38 else 39 echo "$b" 40 return 1 41 fi 42} 43 44ksft_status_merge() 45{ 46 local a=$1; shift 47 local b=$1; shift 48 49 __ksft_status_merge "$a" "$b" \ 50 $ksft_pass $ksft_xfail $ksft_skip $ksft_fail 51} 52 53ksft_exit_status_merge() 54{ 55 local a=$1; shift 56 local b=$1; shift 57 58 __ksft_status_merge "$a" "$b" \ 59 $ksft_xfail $ksft_pass $ksft_skip $ksft_fail 60} 61 62loopy_wait() 63{ 64 local sleep_cmd=$1; shift 65 local timeout_ms=$1; shift 66 67 local start_time="$(date -u +%s%3N)" 68 while true 69 do 70 local out 71 if out=$("$@"); then 72 echo -n "$out" 73 return 0 74 fi 75 76 local current_time="$(date -u +%s%3N)" 77 if ((current_time - start_time > timeout_ms)); then 78 echo -n "$out" 79 return 1 80 fi 81 82 $sleep_cmd 83 done 84} 85 86busywait() 87{ 88 local timeout_ms=$1; shift 89 90 loopy_wait : "$timeout_ms" "$@" 91} 92 93# timeout in seconds 94slowwait() 95{ 96 local timeout_sec=$1; shift 97 98 loopy_wait "sleep 0.1" "$((timeout_sec * 1000))" "$@" 99} 100 101until_counter_is() 102{ 103 local expr=$1; shift 104 local current=$("$@") 105 106 echo $((current)) 107 ((current $expr)) 108} 109 110busywait_for_counter() 111{ 112 local timeout=$1; shift 113 local delta=$1; shift 114 115 local base=$("$@") 116 busywait "$timeout" until_counter_is ">= $((base + delta))" "$@" 117} 118 119slowwait_for_counter() 120{ 121 local timeout=$1; shift 122 local delta=$1; shift 123 124 local base=$("$@") 125 slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@" 126} 127 128remove_ns_list() 129{ 130 local item=$1 131 local ns 132 local ns_list=("${NS_LIST[@]}") 133 NS_LIST=() 134 135 for ns in "${ns_list[@]}"; do 136 if [ "${ns}" != "${item}" ]; then 137 NS_LIST+=("${ns}") 138 fi 139 done 140} 141 142cleanup_ns() 143{ 144 local ns="" 145 local ret=0 146 147 for ns in "$@"; do 148 [ -z "${ns}" ] && continue 149 ip netns pids "${ns}" 2> /dev/null | xargs -r kill || true 150 ip netns delete "${ns}" &> /dev/null || true 151 if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then 152 echo "Warn: Failed to remove namespace $ns" 153 ret=1 154 else 155 remove_ns_list "${ns}" 156 fi 157 done 158 159 return $ret 160} 161 162cleanup_all_ns() 163{ 164 cleanup_ns "${NS_LIST[@]}" 165} 166 167# setup netns with given names as prefix. e.g 168# setup_ns local remote 169setup_ns() 170{ 171 local ns_name="" 172 local ns_list=() 173 for ns_name in "$@"; do 174 # avoid conflicts with local var: internal error 175 if [ "${ns_name}" = "ns_name" ]; then 176 echo "Failed to setup namespace '${ns_name}': invalid name" 177 cleanup_ns "${ns_list[@]}" 178 exit $ksft_fail 179 fi 180 181 # Some test may setup/remove same netns multi times 182 if [ -z "${!ns_name}" ]; then 183 eval "${ns_name}=${ns_name,,}-$(mktemp -u XXXXXX)" 184 else 185 cleanup_ns "${!ns_name}" 186 fi 187 188 if ! ip netns add "${!ns_name}"; then 189 echo "Failed to create namespace $ns_name" 190 cleanup_ns "${ns_list[@]}" 191 return $ksft_skip 192 fi 193 ip -n "${!ns_name}" link set lo up 194 ns_list+=("${!ns_name}") 195 done 196 NS_LIST+=("${ns_list[@]}") 197} 198 199tc_rule_stats_get() 200{ 201 local dev=$1; shift 202 local pref=$1; shift 203 local dir=${1:-ingress}; shift 204 local selector=${1:-.packets}; shift 205 206 tc -j -s filter show dev $dev $dir pref $pref \ 207 | jq ".[1].options.actions[].stats$selector" 208} 209 210tc_rule_handle_stats_get() 211{ 212 local id=$1; shift 213 local handle=$1; shift 214 local selector=${1:-.packets}; shift 215 local netns=${1:-""}; shift 216 217 tc $netns -j -s filter show $id \ 218 | jq ".[] | select(.options.handle == $handle) | \ 219 .options.actions[0].stats$selector" 220} 221