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