lib.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. net_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
  4. source "$net_dir/lib/sh/defer.sh"
  5. ##############################################################################
  6. # Defines
  7. : "${WAIT_TIMEOUT:=20}"
  8. # Whether to pause on after a failure.
  9. : "${PAUSE_ON_FAIL:=no}"
  10. BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms
  11. # Kselftest framework constants.
  12. ksft_pass=0
  13. ksft_fail=1
  14. ksft_xfail=2
  15. ksft_skip=4
  16. # namespace list created by setup_ns
  17. NS_LIST=()
  18. # Exit status to return at the end. Set in case one of the tests fails.
  19. EXIT_STATUS=0
  20. # Per-test return value. Clear at the beginning of each test.
  21. RET=0
  22. ##############################################################################
  23. # Helpers
  24. __ksft_status_merge()
  25. {
  26. local a=$1; shift
  27. local b=$1; shift
  28. local -A weights
  29. local weight=0
  30. local i
  31. for i in "$@"; do
  32. weights[$i]=$((weight++))
  33. done
  34. if [[ ${weights[$a]} -ge ${weights[$b]} ]]; then
  35. echo "$a"
  36. return 0
  37. else
  38. echo "$b"
  39. return 1
  40. fi
  41. }
  42. ksft_status_merge()
  43. {
  44. local a=$1; shift
  45. local b=$1; shift
  46. __ksft_status_merge "$a" "$b" \
  47. $ksft_pass $ksft_xfail $ksft_skip $ksft_fail
  48. }
  49. ksft_exit_status_merge()
  50. {
  51. local a=$1; shift
  52. local b=$1; shift
  53. __ksft_status_merge "$a" "$b" \
  54. $ksft_xfail $ksft_pass $ksft_skip $ksft_fail
  55. }
  56. loopy_wait()
  57. {
  58. local sleep_cmd=$1; shift
  59. local timeout_ms=$1; shift
  60. local start_time="$(date -u +%s%3N)"
  61. while true
  62. do
  63. local out
  64. if out=$("$@"); then
  65. echo -n "$out"
  66. return 0
  67. fi
  68. local current_time="$(date -u +%s%3N)"
  69. if ((current_time - start_time > timeout_ms)); then
  70. echo -n "$out"
  71. return 1
  72. fi
  73. $sleep_cmd
  74. done
  75. }
  76. busywait()
  77. {
  78. local timeout_ms=$1; shift
  79. loopy_wait : "$timeout_ms" "$@"
  80. }
  81. # timeout in seconds
  82. slowwait()
  83. {
  84. local timeout_sec=$1; shift
  85. loopy_wait "sleep 0.1" "$((timeout_sec * 1000))" "$@"
  86. }
  87. until_counter_is()
  88. {
  89. local expr=$1; shift
  90. local current=$("$@")
  91. echo $((current))
  92. ((current $expr))
  93. }
  94. busywait_for_counter()
  95. {
  96. local timeout=$1; shift
  97. local delta=$1; shift
  98. local base=$("$@")
  99. busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
  100. }
  101. slowwait_for_counter()
  102. {
  103. local timeout=$1; shift
  104. local delta=$1; shift
  105. local base=$("$@")
  106. slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@"
  107. }
  108. # Check for existence of tools which are built as part of selftests
  109. # but may also already exist in $PATH
  110. check_gen_prog()
  111. {
  112. local prog_name=$1; shift
  113. if ! which $prog_name >/dev/null 2>/dev/null; then
  114. PATH=$PWD:$PATH
  115. if ! which $prog_name >/dev/null; then
  116. echo "'$prog_name' command not found; skipping tests"
  117. exit $ksft_skip
  118. fi
  119. fi
  120. }
  121. remove_ns_list()
  122. {
  123. local item=$1
  124. local ns
  125. local ns_list=("${NS_LIST[@]}")
  126. NS_LIST=()
  127. for ns in "${ns_list[@]}"; do
  128. if [ "${ns}" != "${item}" ]; then
  129. NS_LIST+=("${ns}")
  130. fi
  131. done
  132. }
  133. cleanup_ns()
  134. {
  135. local ns=""
  136. local ret=0
  137. for ns in "$@"; do
  138. [ -z "${ns}" ] && continue
  139. ip netns pids "${ns}" 2> /dev/null | xargs -r kill || true
  140. ip netns delete "${ns}" &> /dev/null || true
  141. if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
  142. echo "Warn: Failed to remove namespace $ns"
  143. ret=1
  144. else
  145. remove_ns_list "${ns}"
  146. fi
  147. done
  148. return $ret
  149. }
  150. cleanup_all_ns()
  151. {
  152. cleanup_ns "${NS_LIST[@]}"
  153. }
  154. # setup netns with given names as prefix. e.g
  155. # setup_ns local remote
  156. setup_ns()
  157. {
  158. local ns_name=""
  159. local ns_list=()
  160. for ns_name in "$@"; do
  161. # avoid conflicts with local var: internal error
  162. if [ "${ns_name}" = "ns_name" ]; then
  163. echo "Failed to setup namespace '${ns_name}': invalid name"
  164. cleanup_ns "${ns_list[@]}"
  165. exit $ksft_fail
  166. fi
  167. # Some test may setup/remove same netns multi times
  168. if [ -z "${!ns_name}" ]; then
  169. eval "${ns_name}=${ns_name,,}-$(mktemp -u XXXXXX)"
  170. else
  171. cleanup_ns "${!ns_name}"
  172. fi
  173. if ! ip netns add "${!ns_name}"; then
  174. echo "Failed to create namespace $ns_name"
  175. cleanup_ns "${ns_list[@]}"
  176. return $ksft_skip
  177. fi
  178. ip -n "${!ns_name}" link set lo up
  179. ip netns exec "${!ns_name}" sysctl -wq net.ipv4.conf.all.rp_filter=0
  180. ip netns exec "${!ns_name}" sysctl -wq net.ipv4.conf.default.rp_filter=0
  181. ns_list+=("${!ns_name}")
  182. done
  183. NS_LIST+=("${ns_list[@]}")
  184. }
  185. # Create netdevsim with given id and net namespace.
  186. create_netdevsim() {
  187. local id="$1"
  188. local ns="$2"
  189. modprobe netdevsim &> /dev/null
  190. udevadm settle
  191. echo "$id 1" | ip netns exec $ns tee /sys/bus/netdevsim/new_device >/dev/null
  192. local dev=$(ip netns exec $ns ls /sys/bus/netdevsim/devices/netdevsim$id/net)
  193. ip -netns $ns link set dev $dev name nsim$id
  194. ip -netns $ns link set dev nsim$id up
  195. echo nsim$id
  196. }
  197. create_netdevsim_port() {
  198. local nsim_id="$1"
  199. local ns="$2"
  200. local port_id="$3"
  201. local perm_addr="$4"
  202. local orig_dev
  203. local new_dev
  204. local nsim_path
  205. nsim_path="/sys/bus/netdevsim/devices/netdevsim$nsim_id"
  206. echo "$port_id $perm_addr" | ip netns exec "$ns" tee "$nsim_path"/new_port > /dev/null || return 1
  207. orig_dev=$(ip netns exec "$ns" find "$nsim_path"/net/ -maxdepth 1 -name 'e*' | tail -n 1)
  208. orig_dev=$(basename "$orig_dev")
  209. new_dev="nsim${nsim_id}p$port_id"
  210. ip -netns "$ns" link set dev "$orig_dev" name "$new_dev"
  211. ip -netns "$ns" link set dev "$new_dev" up
  212. echo "$new_dev"
  213. }
  214. # Remove netdevsim with given id.
  215. cleanup_netdevsim() {
  216. local id="$1"
  217. if [ -d "/sys/bus/netdevsim/devices/netdevsim$id/net" ]; then
  218. echo "$id" > /sys/bus/netdevsim/del_device
  219. fi
  220. }
  221. tc_rule_stats_get()
  222. {
  223. local dev=$1; shift
  224. local pref=$1; shift
  225. local dir=${1:-ingress}; shift
  226. local selector=${1:-.packets}; shift
  227. tc -j -s filter show dev $dev $dir pref $pref \
  228. | jq ".[] | select(.options.actions) |
  229. .options.actions[].stats$selector"
  230. }
  231. tc_rule_handle_stats_get()
  232. {
  233. local id=$1; shift
  234. local handle=$1; shift
  235. local selector=${1:-.packets}; shift
  236. local netns=${1:-""}; shift
  237. tc $netns -j -s filter show $id \
  238. | jq ".[] | select(.options.handle == $handle) | \
  239. .options.actions[0].stats$selector"
  240. }
  241. # attach a qdisc with two children match/no-match and a flower filter to match
  242. tc_set_flower_counter() {
  243. local -r ns=$1
  244. local -r ipver=$2
  245. local -r dev=$3
  246. local -r flower_expr=$4
  247. tc -n $ns qdisc add dev $dev root handle 1: prio bands 2 \
  248. priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  249. tc -n $ns qdisc add dev $dev parent 1:1 handle 11: pfifo
  250. tc -n $ns qdisc add dev $dev parent 1:2 handle 12: pfifo
  251. tc -n $ns filter add dev $dev parent 1: protocol ipv$ipver \
  252. flower $flower_expr classid 1:2
  253. }
  254. tc_get_flower_counter() {
  255. local -r ns=$1
  256. local -r dev=$2
  257. tc -n $ns -j -s qdisc show dev $dev handle 12: | jq .[0].packets
  258. }
  259. ret_set_ksft_status()
  260. {
  261. local ksft_status=$1; shift
  262. local msg=$1; shift
  263. RET=$(ksft_status_merge $RET $ksft_status)
  264. if (( $? )); then
  265. retmsg=$msg
  266. fi
  267. }
  268. log_test_result()
  269. {
  270. local test_name=$1; shift
  271. local opt_str=$1; shift
  272. local result=$1; shift
  273. local retmsg=$1
  274. printf "TEST: %-60s [%s]\n" "$test_name $opt_str" "$result"
  275. if [[ $retmsg ]]; then
  276. printf "\t%s\n" "$retmsg"
  277. fi
  278. }
  279. pause_on_fail()
  280. {
  281. if [[ $PAUSE_ON_FAIL == yes ]]; then
  282. echo "Hit enter to continue, 'q' to quit"
  283. read a
  284. [[ $a == q ]] && exit 1
  285. fi
  286. }
  287. handle_test_result_pass()
  288. {
  289. local test_name=$1; shift
  290. local opt_str=$1; shift
  291. log_test_result "$test_name" "$opt_str" " OK "
  292. }
  293. handle_test_result_fail()
  294. {
  295. local test_name=$1; shift
  296. local opt_str=$1; shift
  297. log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
  298. pause_on_fail
  299. }
  300. handle_test_result_xfail()
  301. {
  302. local test_name=$1; shift
  303. local opt_str=$1; shift
  304. log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
  305. pause_on_fail
  306. }
  307. handle_test_result_skip()
  308. {
  309. local test_name=$1; shift
  310. local opt_str=$1; shift
  311. log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
  312. }
  313. log_test()
  314. {
  315. local test_name=$1
  316. local opt_str=$2
  317. if [[ $# -eq 2 ]]; then
  318. opt_str="($opt_str)"
  319. fi
  320. if ((RET == ksft_pass)); then
  321. handle_test_result_pass "$test_name" "$opt_str"
  322. elif ((RET == ksft_xfail)); then
  323. handle_test_result_xfail "$test_name" "$opt_str"
  324. elif ((RET == ksft_skip)); then
  325. handle_test_result_skip "$test_name" "$opt_str"
  326. else
  327. handle_test_result_fail "$test_name" "$opt_str"
  328. fi
  329. EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
  330. return $RET
  331. }
  332. log_test_skip()
  333. {
  334. RET=$ksft_skip retmsg= log_test "$@"
  335. }
  336. log_test_xfail()
  337. {
  338. RET=$ksft_xfail retmsg= log_test "$@"
  339. }
  340. log_info()
  341. {
  342. local msg=$1
  343. echo "INFO: $msg"
  344. }
  345. tests_run()
  346. {
  347. local current_test
  348. for current_test in ${TESTS:-$ALL_TESTS}; do
  349. in_defer_scope \
  350. $current_test
  351. done
  352. }
  353. # Whether FAILs should be interpreted as XFAILs. Internal.
  354. FAIL_TO_XFAIL=
  355. check_err()
  356. {
  357. local err=$1
  358. local msg=$2
  359. if ((err)); then
  360. if [[ $FAIL_TO_XFAIL = yes ]]; then
  361. ret_set_ksft_status $ksft_xfail "$msg"
  362. else
  363. ret_set_ksft_status $ksft_fail "$msg"
  364. fi
  365. fi
  366. }
  367. check_fail()
  368. {
  369. local err=$1
  370. local msg=$2
  371. check_err $((!err)) "$msg"
  372. }
  373. check_err_fail()
  374. {
  375. local should_fail=$1; shift
  376. local err=$1; shift
  377. local what=$1; shift
  378. if ((should_fail)); then
  379. check_fail $err "$what succeeded, but should have failed"
  380. else
  381. check_err $err "$what failed"
  382. fi
  383. }
  384. xfail()
  385. {
  386. FAIL_TO_XFAIL=yes "$@"
  387. }
  388. xfail_on_slow()
  389. {
  390. if [[ $KSFT_MACHINE_SLOW = yes ]]; then
  391. FAIL_TO_XFAIL=yes "$@"
  392. else
  393. "$@"
  394. fi
  395. }
  396. omit_on_slow()
  397. {
  398. if [[ $KSFT_MACHINE_SLOW != yes ]]; then
  399. "$@"
  400. fi
  401. }
  402. xfail_on_veth()
  403. {
  404. local dev=$1; shift
  405. local kind
  406. kind=$(ip -j -d link show dev $dev |
  407. jq -r '.[].linkinfo.info_kind')
  408. if [[ $kind = veth ]]; then
  409. FAIL_TO_XFAIL=yes "$@"
  410. else
  411. "$@"
  412. fi
  413. }
  414. mac_get()
  415. {
  416. local if_name=$1
  417. ip -j link show dev $if_name | jq -r '.[]["address"]'
  418. }
  419. kill_process()
  420. {
  421. local pid=$1; shift
  422. # Suppress noise from killing the process.
  423. { kill $pid && wait $pid; } 2>/dev/null
  424. }
  425. check_command()
  426. {
  427. local cmd=$1; shift
  428. if [[ ! -x "$(command -v "$cmd")" ]]; then
  429. log_test_skip "$cmd not installed"
  430. return $EXIT_STATUS
  431. fi
  432. }
  433. require_command()
  434. {
  435. local cmd=$1; shift
  436. if ! check_command "$cmd"; then
  437. exit $EXIT_STATUS
  438. fi
  439. }
  440. adf_ip_link_add()
  441. {
  442. local name=$1; shift
  443. ip link add name "$name" "$@" && \
  444. defer ip link del dev "$name"
  445. }
  446. adf_ip_link_set_master()
  447. {
  448. local member=$1; shift
  449. local master=$1; shift
  450. ip link set dev "$member" master "$master" && \
  451. defer ip link set dev "$member" nomaster
  452. }
  453. adf_ip_link_set_addr()
  454. {
  455. local name=$1; shift
  456. local addr=$1; shift
  457. local old_addr=$(mac_get "$name")
  458. ip link set dev "$name" address "$addr" && \
  459. defer ip link set dev "$name" address "$old_addr"
  460. }
  461. ip_link_has_flag()
  462. {
  463. local name=$1; shift
  464. local flag=$1; shift
  465. local state=$(ip -j link show "$name" |
  466. jq --arg flag "$flag" 'any(.[].flags[]; . == $flag)')
  467. [[ $state == true ]]
  468. }
  469. ip_link_is_up()
  470. {
  471. ip_link_has_flag "$1" UP
  472. }
  473. adf_ip_link_set_up()
  474. {
  475. local name=$1; shift
  476. if ! ip_link_is_up "$name"; then
  477. ip link set dev "$name" up && \
  478. defer ip link set dev "$name" down
  479. fi
  480. }
  481. adf_ip_link_set_down()
  482. {
  483. local name=$1; shift
  484. if ip_link_is_up "$name"; then
  485. ip link set dev "$name" down && \
  486. defer ip link set dev "$name" up
  487. fi
  488. }
  489. adf_ip_addr_add()
  490. {
  491. local name=$1; shift
  492. ip addr add dev "$name" "$@" && \
  493. defer ip addr del dev "$name" "$@"
  494. }
  495. adf_ip_route_add()
  496. {
  497. ip route add "$@" && \
  498. defer ip route del "$@"
  499. }
  500. adf_bridge_vlan_add()
  501. {
  502. bridge vlan add "$@" && \
  503. defer bridge vlan del "$@"
  504. }
  505. wait_local_port_listen()
  506. {
  507. local listener_ns="${1}"
  508. local port="${2}"
  509. local protocol="${3}"
  510. local pattern
  511. local i
  512. pattern=":$(printf "%04X" "${port}") "
  513. # for tcp protocol additionally check the socket state
  514. [ ${protocol} = "tcp" ] && pattern="${pattern}0A"
  515. for i in $(seq 10); do
  516. if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \
  517. /proc/net/"${protocol}"* | grep -q "${pattern}"; then
  518. break
  519. fi
  520. sleep 0.1
  521. done
  522. }
  523. cmd_jq()
  524. {
  525. local cmd=$1
  526. local jq_exp=$2
  527. local jq_opts=$3
  528. local ret
  529. local output
  530. output="$($cmd)"
  531. # it the command fails, return error right away
  532. ret=$?
  533. if [[ $ret -ne 0 ]]; then
  534. return $ret
  535. fi
  536. output=$(echo $output | jq -r $jq_opts "$jq_exp")
  537. ret=$?
  538. if [[ $ret -ne 0 ]]; then
  539. return $ret
  540. fi
  541. echo $output
  542. # return success only in case of non-empty output
  543. [ ! -z "$output" ]
  544. }