| 1 | |
| 2 | |
| 3 |
|
| 4 | net_dir=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
|
| 5 | source "$net_dir/lib/sh/defer.sh"
|
| 6 |
|
| 7 | |
| 8 | |
| 9 |
|
| 10 | : "${WAIT_TIMEOUT:=20}"
|
| 11 |
|
| 12 | |
| 13 | : "${PAUSE_ON_FAIL:=no}"
|
| 14 |
|
| 15 | BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) |
| 16 |
|
| 17 | |
| 18 | ksft_pass=0
|
| 19 | ksft_fail=1
|
| 20 | ksft_xfail=2
|
| 21 | ksft_skip=4
|
| 22 |
|
| 23 | |
| 24 | NS_LIST=()
|
| 25 |
|
| 26 | |
| 27 | EXIT_STATUS=0
|
| 28 | |
| 29 | RET=0
|
| 30 |
|
| 31 | |
| 32 | |
| 33 |
|
| 34 | __ksft_status_merge()
|
| 35 | {
|
| 36 | local a=$1; shift
|
| 37 | local b=$1; shift
|
| 38 | local -A weights
|
| 39 | local weight=0
|
| 40 |
|
| 41 | local i
|
| 42 | for i in "$@"; do
|
| 43 | weights[$i]=$((weight++))
|
| 44 | done
|
| 45 |
|
| 46 | if [[ ${weights[$a]} -ge ${weights[$b]} ]]; then
|
| 47 | echo "$a"
|
| 48 | return 0
|
| 49 | else
|
| 50 | echo "$b"
|
| 51 | return 1
|
| 52 | fi
|
| 53 | }
|
| 54 |
|
| 55 | ksft_status_merge()
|
| 56 | {
|
| 57 | local a=$1; shift
|
| 58 | local b=$1; shift
|
| 59 |
|
| 60 | __ksft_status_merge "$a" "$b" \
|
| 61 | $ksft_pass $ksft_xfail $ksft_skip $ksft_fail
|
| 62 | }
|
| 63 |
|
| 64 | ksft_exit_status_merge()
|
| 65 | {
|
| 66 | local a=$1; shift
|
| 67 | local b=$1; shift
|
| 68 |
|
| 69 | __ksft_status_merge "$a" "$b" \
|
| 70 | $ksft_xfail $ksft_pass $ksft_skip $ksft_fail
|
| 71 | }
|
| 72 |
|
| 73 | timestamp_ms()
|
| 74 | {
|
| 75 | local now
|
| 76 | local seconds
|
| 77 | local nanoseconds
|
| 78 |
|
| 79 | now=$(date -u +%s:%N) || return
|
| 80 | seconds=${now%:*}
|
| 81 | nanoseconds=${now#*:}
|
| 82 |
|
| 83 | if [[ $nanoseconds =~ ^[0-9]+$ ]]; then
|
| 84 | nanoseconds=${nanoseconds:0:9}
|
| 85 | else
|
| 86 | nanoseconds=0
|
| 87 | fi
|
| 88 |
|
| 89 | echo $((seconds * 1000 + 10#$nanoseconds / 1000000))
|
| 90 | }
|
| 91 |
|
| 92 | loopy_wait()
|
| 93 | {
|
| 94 | local sleep_cmd=$1; shift
|
| 95 | local timeout_ms=$1; shift
|
| 96 | local start_time
|
| 97 | local current_time
|
| 98 |
|
| 99 | start_time=$(timestamp_ms) || return
|
| 100 | while true
|
| 101 | do
|
| 102 | local out
|
| 103 | if out=$("$@"); then
|
| 104 | echo -n "$out"
|
| 105 | return 0
|
| 106 | fi
|
| 107 |
|
| 108 | current_time=$(timestamp_ms) || return
|
| 109 | if ((current_time - start_time > timeout_ms)); then
|
| 110 | echo -n "$out"
|
| 111 | return 1
|
| 112 | fi
|
| 113 |
|
| 114 | $sleep_cmd
|
| 115 | done
|
| 116 | }
|
| 117 |
|
| 118 | busywait()
|
| 119 | {
|
| 120 | local timeout_ms=$1; shift
|
| 121 |
|
| 122 | loopy_wait : "$timeout_ms" "$@"
|
| 123 | }
|
| 124 |
|
| 125 | |
| 126 | slowwait()
|
| 127 | {
|
| 128 | local timeout_sec=$1; shift
|
| 129 |
|
| 130 | loopy_wait "sleep 0.1" "$((timeout_sec * 1000))" "$@"
|
| 131 | }
|
| 132 |
|
| 133 | until_counter_is()
|
| 134 | {
|
| 135 | local expr=$1; shift
|
| 136 | local current=$("$@")
|
| 137 |
|
| 138 | echo $((current))
|
| 139 | ((current $expr))
|
| 140 | }
|
| 141 |
|
| 142 | busywait_for_counter()
|
| 143 | {
|
| 144 | local timeout=$1; shift
|
| 145 | local delta=$1; shift
|
| 146 |
|
| 147 | local base=$("$@")
|
| 148 | busywait "$timeout" until_counter_is ">= $((base + delta))" "$@"
|
| 149 | }
|
| 150 |
|
| 151 | slowwait_for_counter()
|
| 152 | {
|
| 153 | local timeout=$1; shift
|
| 154 | local delta=$1; shift
|
| 155 |
|
| 156 | local base=$("$@")
|
| 157 | slowwait "$timeout" until_counter_is ">= $((base + delta))" "$@"
|
| 158 | }
|
| 159 |
|
| 160 | |
| 161 | |
| 162 | check_gen_prog()
|
| 163 | {
|
| 164 | local prog_name=$1; shift
|
| 165 |
|
| 166 | if ! which $prog_name >/dev/null 2>/dev/null; then
|
| 167 | PATH=$PWD:$PATH
|
| 168 | if ! which $prog_name >/dev/null; then
|
| 169 | echo "'$prog_name' command not found; skipping tests"
|
| 170 | exit $ksft_skip
|
| 171 | fi
|
| 172 | fi
|
| 173 | }
|
| 174 |
|
| 175 | remove_ns_list()
|
| 176 | {
|
| 177 | local item=$1
|
| 178 | local ns
|
| 179 | local ns_list=("${NS_LIST[@]}")
|
| 180 | NS_LIST=()
|
| 181 |
|
| 182 | for ns in "${ns_list[@]}"; do
|
| 183 | if [ "${ns}" != "${item}" ]; then
|
| 184 | NS_LIST+=("${ns}")
|
| 185 | fi
|
| 186 | done
|
| 187 | }
|
| 188 |
|
| 189 | cleanup_ns()
|
| 190 | {
|
| 191 | local ns=""
|
| 192 | local ret=0
|
| 193 |
|
| 194 | for ns in "$@"; do
|
| 195 | [ -z "${ns}" ] && continue
|
| 196 | ip netns pids "${ns}" 2> /dev/null | xargs -r kill || true
|
| 197 | ip netns delete "${ns}" &> /dev/null || true
|
| 198 | if ! busywait $BUSYWAIT_TIMEOUT ip netns list \| grep -vq "^$ns$" &> /dev/null; then
|
| 199 | echo "Warn: Failed to remove namespace $ns"
|
| 200 | ret=1
|
| 201 | else
|
| 202 | remove_ns_list "${ns}"
|
| 203 | fi
|
| 204 | done
|
| 205 |
|
| 206 | return $ret
|
| 207 | }
|
| 208 |
|
| 209 | cleanup_all_ns()
|
| 210 | {
|
| 211 | cleanup_ns "${NS_LIST[@]}"
|
| 212 | }
|
| 213 |
|
| 214 | |
| 215 | |
| 216 | setup_ns()
|
| 217 | {
|
| 218 | local ns_name=""
|
| 219 | local ns_list=()
|
| 220 | for ns_name in "$@"; do
|
| 221 | |
| 222 | if [ "${ns_name}" = "ns_name" ]; then
|
| 223 | echo "Failed to setup namespace '${ns_name}': invalid name"
|
| 224 | cleanup_ns "${ns_list[@]}"
|
| 225 | exit $ksft_fail
|
| 226 | fi
|
| 227 |
|
| 228 | |
| 229 | if [ -z "${!ns_name}" ]; then
|
| 230 | eval "${ns_name}=${ns_name,,}-$(mktemp -u XXXXXX)"
|
| 231 | else
|
| 232 | cleanup_ns "${!ns_name}"
|
| 233 | fi
|
| 234 |
|
| 235 | if ! ip netns add "${!ns_name}"; then
|
| 236 | echo "Failed to create namespace $ns_name"
|
| 237 | cleanup_ns "${ns_list[@]}"
|
| 238 | return $ksft_skip
|
| 239 | fi
|
| 240 | ip -n "${!ns_name}" link set lo up
|
| 241 | ip netns exec "${!ns_name}" sysctl -wq net.ipv4.conf.all.rp_filter=0
|
| 242 | ip netns exec "${!ns_name}" sysctl -wq net.ipv4.conf.default.rp_filter=0
|
| 243 | ns_list+=("${!ns_name}")
|
| 244 | done
|
| 245 | NS_LIST+=("${ns_list[@]}")
|
| 246 | }
|
| 247 |
|
| 248 | in_all_ns()
|
| 249 | {
|
| 250 | local ret=0
|
| 251 | local ns_list=("${NS_LIST[@]}")
|
| 252 |
|
| 253 | for ns in "${ns_list[@]}"; do
|
| 254 | ip netns exec "${ns}" "$@"
|
| 255 | (( ret = ret || $? ))
|
| 256 | done
|
| 257 |
|
| 258 | return "${ret}"
|
| 259 | }
|
| 260 |
|
| 261 | |
| 262 | create_netdevsim() {
|
| 263 | local id="$1"
|
| 264 | local ns="$2"
|
| 265 |
|
| 266 | modprobe netdevsim &> /dev/null
|
| 267 | udevadm settle
|
| 268 |
|
| 269 | echo "$id 1" | ip netns exec $ns tee /sys/bus/netdevsim/new_device >/dev/null
|
| 270 | local dev=$(ip netns exec $ns ls /sys/bus/netdevsim/devices/netdevsim$id/net)
|
| 271 | ip -netns $ns link set dev $dev name nsim$id
|
| 272 | ip -netns $ns link set dev nsim$id up
|
| 273 |
|
| 274 | echo nsim$id
|
| 275 | }
|
| 276 |
|
| 277 | create_netdevsim_port() {
|
| 278 | local nsim_id="$1"
|
| 279 | local ns="$2"
|
| 280 | local port_id="$3"
|
| 281 | local perm_addr="$4"
|
| 282 | local orig_dev
|
| 283 | local new_dev
|
| 284 | local nsim_path
|
| 285 |
|
| 286 | nsim_path="/sys/bus/netdevsim/devices/netdevsim$nsim_id"
|
| 287 |
|
| 288 | echo "$port_id $perm_addr" | ip netns exec "$ns" tee "$nsim_path"/new_port > /dev/null || return 1
|
| 289 |
|
| 290 | orig_dev=$(ip netns exec "$ns" find "$nsim_path"/net/ -maxdepth 1 -name 'e*' | tail -n 1)
|
| 291 | orig_dev=$(basename "$orig_dev")
|
| 292 | new_dev="nsim${nsim_id}p$port_id"
|
| 293 |
|
| 294 | ip -netns "$ns" link set dev "$orig_dev" name "$new_dev"
|
| 295 | ip -netns "$ns" link set dev "$new_dev" up
|
| 296 |
|
| 297 | echo "$new_dev"
|
| 298 | }
|
| 299 |
|
| 300 | |
| 301 | cleanup_netdevsim() {
|
| 302 | local id="$1"
|
| 303 |
|
| 304 | if [ -d "/sys/bus/netdevsim/devices/netdevsim$id/net" ]; then
|
| 305 | echo "$id" > /sys/bus/netdevsim/del_device
|
| 306 | fi
|
| 307 | }
|
| 308 |
|
| 309 | tc_rule_stats_get()
|
| 310 | {
|
| 311 | local dev=$1; shift
|
| 312 | local pref=$1; shift
|
| 313 | local dir=${1:-ingress}; shift
|
| 314 | local selector=${1:-.packets}; shift
|
| 315 |
|
| 316 | tc -j -s filter show dev $dev $dir pref $pref \
|
| 317 | | jq ".[] | select(.options.actions) |
|
| 318 | .options.actions[].stats$selector"
|
| 319 | }
|
| 320 |
|
| 321 | tc_rule_handle_stats_get()
|
| 322 | {
|
| 323 | local id=$1; shift
|
| 324 | local handle=$1; shift
|
| 325 | local selector=${1:-.packets}; shift
|
| 326 | local netns=${1:-""}; shift
|
| 327 |
|
| 328 | tc $netns -j -s filter show $id \
|
| 329 | | jq ".[] | select(.options.handle == $handle) | \
|
| 330 | .options.actions[0].stats$selector"
|
| 331 | }
|
| 332 |
|
| 333 | |
| 334 | tc_set_flower_counter() {
|
| 335 | local -r ns=$1
|
| 336 | local -r ipver=$2
|
| 337 | local -r dev=$3
|
| 338 | local -r flower_expr=$4
|
| 339 |
|
| 340 | tc -n $ns qdisc add dev $dev root handle 1: prio bands 2 \
|
| 341 | priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
| 342 |
|
| 343 | tc -n $ns qdisc add dev $dev parent 1:1 handle 11: pfifo
|
| 344 | tc -n $ns qdisc add dev $dev parent 1:2 handle 12: pfifo
|
| 345 |
|
| 346 | tc -n $ns filter add dev $dev parent 1: protocol ipv$ipver \
|
| 347 | flower $flower_expr classid 1:2
|
| 348 | }
|
| 349 |
|
| 350 | tc_get_flower_counter() {
|
| 351 | local -r ns=$1
|
| 352 | local -r dev=$2
|
| 353 |
|
| 354 | tc -n $ns -j -s qdisc show dev $dev handle 12: | jq .[0].packets
|
| 355 | }
|
| 356 |
|
| 357 | ret_set_ksft_status()
|
| 358 | {
|
| 359 | local ksft_status=$1; shift
|
| 360 | local msg=$1; shift
|
| 361 |
|
| 362 | RET=$(ksft_status_merge $RET $ksft_status)
|
| 363 | if (( $? )); then
|
| 364 | retmsg=$msg
|
| 365 | fi
|
| 366 | }
|
| 367 |
|
| 368 | log_test_result()
|
| 369 | {
|
| 370 | local test_name=$1; shift
|
| 371 | local opt_str=$1; shift
|
| 372 | local result=$1; shift
|
| 373 | local retmsg=$1
|
| 374 |
|
| 375 | printf "TEST: %-60s [%s]\n" "$test_name $opt_str" "$result"
|
| 376 | if [[ $retmsg ]]; then
|
| 377 | printf "\t%s\n" "$retmsg"
|
| 378 | fi
|
| 379 | }
|
| 380 |
|
| 381 | pause_on_fail()
|
| 382 | {
|
| 383 | if [[ $PAUSE_ON_FAIL == yes ]]; then
|
| 384 | echo "Hit enter to continue, 'q' to quit"
|
| 385 | read a
|
| 386 | [[ $a == q ]] && exit 1
|
| 387 | fi
|
| 388 | }
|
| 389 |
|
| 390 | handle_test_result_pass()
|
| 391 | {
|
| 392 | local test_name=$1; shift
|
| 393 | local opt_str=$1; shift
|
| 394 |
|
| 395 | log_test_result "$test_name" "$opt_str" " OK "
|
| 396 | }
|
| 397 |
|
| 398 | handle_test_result_fail()
|
| 399 | {
|
| 400 | local test_name=$1; shift
|
| 401 | local opt_str=$1; shift
|
| 402 |
|
| 403 | log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
|
| 404 | pause_on_fail
|
| 405 | }
|
| 406 |
|
| 407 | handle_test_result_xfail()
|
| 408 | {
|
| 409 | local test_name=$1; shift
|
| 410 | local opt_str=$1; shift
|
| 411 |
|
| 412 | log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
|
| 413 | pause_on_fail
|
| 414 | }
|
| 415 |
|
| 416 | handle_test_result_skip()
|
| 417 | {
|
| 418 | local test_name=$1; shift
|
| 419 | local opt_str=$1; shift
|
| 420 |
|
| 421 | log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
|
| 422 | }
|
| 423 |
|
| 424 | log_test()
|
| 425 | {
|
| 426 | local test_name=$1
|
| 427 | local opt_str=$2
|
| 428 |
|
| 429 | if [[ $# -eq 2 ]]; then
|
| 430 | opt_str="($opt_str)"
|
| 431 | fi
|
| 432 |
|
| 433 | if ((RET == ksft_pass)); then
|
| 434 | handle_test_result_pass "$test_name" "$opt_str"
|
| 435 | elif ((RET == ksft_xfail)); then
|
| 436 | handle_test_result_xfail "$test_name" "$opt_str"
|
| 437 | elif ((RET == ksft_skip)); then
|
| 438 | handle_test_result_skip "$test_name" "$opt_str"
|
| 439 | else
|
| 440 | handle_test_result_fail "$test_name" "$opt_str"
|
| 441 | fi
|
| 442 |
|
| 443 | EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
|
| 444 | return $RET
|
| 445 | }
|
| 446 |
|
| 447 | log_test_skip()
|
| 448 | {
|
| 449 | RET=$ksft_skip retmsg= log_test "$@"
|
| 450 | }
|
| 451 |
|
| 452 | log_test_xfail()
|
| 453 | {
|
| 454 | RET=$ksft_xfail retmsg= log_test "$@"
|
| 455 | }
|
| 456 |
|
| 457 | log_info()
|
| 458 | {
|
| 459 | local msg=$1
|
| 460 |
|
| 461 | echo "INFO: $msg"
|
| 462 | }
|
| 463 |
|
| 464 | tests_run()
|
| 465 | {
|
| 466 | local current_test
|
| 467 |
|
| 468 | for current_test in ${TESTS:-$ALL_TESTS}; do
|
| 469 | in_defer_scope \
|
| 470 | $current_test
|
| 471 | done
|
| 472 | }
|
| 473 |
|
| 474 | |
| 475 | FAIL_TO_XFAIL=
|
| 476 |
|
| 477 | check_err()
|
| 478 | {
|
| 479 | local err=$1
|
| 480 | local msg=$2
|
| 481 |
|
| 482 | if ((err)); then
|
| 483 | if [[ $FAIL_TO_XFAIL = yes ]]; then
|
| 484 | ret_set_ksft_status $ksft_xfail "$msg"
|
| 485 | else
|
| 486 | ret_set_ksft_status $ksft_fail "$msg"
|
| 487 | fi
|
| 488 | fi
|
| 489 | }
|
| 490 |
|
| 491 | check_fail()
|
| 492 | {
|
| 493 | local err=$1
|
| 494 | local msg=$2
|
| 495 |
|
| 496 | check_err $((!err)) "$msg"
|
| 497 | }
|
| 498 |
|
| 499 | check_err_fail()
|
| 500 | {
|
| 501 | local should_fail=$1; shift
|
| 502 | local err=$1; shift
|
| 503 | local what=$1; shift
|
| 504 |
|
| 505 | if ((should_fail)); then
|
| 506 | check_fail $err "$what succeeded, but should have failed"
|
| 507 | else
|
| 508 | check_err $err "$what failed"
|
| 509 | fi
|
| 510 | }
|
| 511 |
|
| 512 | xfail()
|
| 513 | {
|
| 514 | FAIL_TO_XFAIL=yes "$@"
|
| 515 | }
|
| 516 |
|
| 517 | xfail_on_slow()
|
| 518 | {
|
| 519 | if [[ $KSFT_MACHINE_SLOW = yes ]]; then
|
| 520 | FAIL_TO_XFAIL=yes "$@"
|
| 521 | else
|
| 522 | "$@"
|
| 523 | fi
|
| 524 | }
|
| 525 |
|
| 526 | omit_on_slow()
|
| 527 | {
|
| 528 | if [[ $KSFT_MACHINE_SLOW != yes ]]; then
|
| 529 | "$@"
|
| 530 | fi
|
| 531 | }
|
| 532 |
|
| 533 | xfail_on_veth()
|
| 534 | {
|
| 535 | local dev=$1; shift
|
| 536 | local kind
|
| 537 |
|
| 538 | kind=$(ip -j -d link show dev $dev |
|
| 539 | jq -r '.[].linkinfo.info_kind')
|
| 540 | if [[ $kind = veth ]]; then
|
| 541 | FAIL_TO_XFAIL=yes "$@"
|
| 542 | else
|
| 543 | "$@"
|
| 544 | fi
|
| 545 | }
|
| 546 |
|
| 547 | mac_get()
|
| 548 | {
|
| 549 | local if_name=$1
|
| 550 |
|
| 551 | run_on "$if_name" \
|
| 552 | ip -j link show dev "$if_name" | jq -r '.[]["address"]'
|
| 553 | }
|
| 554 |
|
| 555 | kill_process()
|
| 556 | {
|
| 557 | local pid=$1; shift
|
| 558 |
|
| 559 | |
| 560 | { kill $pid && wait $pid; } 2>/dev/null
|
| 561 | }
|
| 562 |
|
| 563 | check_command()
|
| 564 | {
|
| 565 | local cmd=$1; shift
|
| 566 |
|
| 567 | if [[ ! -x "$(command -v "$cmd")" ]]; then
|
| 568 | log_test_skip "$cmd not installed"
|
| 569 | return $EXIT_STATUS
|
| 570 | fi
|
| 571 | }
|
| 572 |
|
| 573 | require_command()
|
| 574 | {
|
| 575 | local cmd=$1; shift
|
| 576 |
|
| 577 | if ! check_command "$cmd"; then
|
| 578 | exit $EXIT_STATUS
|
| 579 | fi
|
| 580 | }
|
| 581 |
|
| 582 | adf_ip_link_add()
|
| 583 | {
|
| 584 | local name=$1; shift
|
| 585 |
|
| 586 | ip link add name "$name" "$@" && \
|
| 587 | defer ip link del dev "$name"
|
| 588 | }
|
| 589 |
|
| 590 | adf_ip_link_set_master()
|
| 591 | {
|
| 592 | local member=$1; shift
|
| 593 | local master=$1; shift
|
| 594 |
|
| 595 | ip link set dev "$member" master "$master" && \
|
| 596 | defer ip link set dev "$member" nomaster
|
| 597 | }
|
| 598 |
|
| 599 | adf_ip_link_set_addr()
|
| 600 | {
|
| 601 | local name=$1; shift
|
| 602 | local addr=$1; shift
|
| 603 |
|
| 604 | local old_addr=$(mac_get "$name")
|
| 605 | ip link set dev "$name" address "$addr" && \
|
| 606 | defer ip link set dev "$name" address "$old_addr"
|
| 607 | }
|
| 608 |
|
| 609 | ip_link_has_flag()
|
| 610 | {
|
| 611 | local name=$1; shift
|
| 612 | local flag=$1; shift
|
| 613 |
|
| 614 | local state=$(ip -j link show "$name" |
|
| 615 | jq --arg flag "$flag" 'any(.[].flags[]; . == $flag)')
|
| 616 | [[ $state == true ]]
|
| 617 | }
|
| 618 |
|
| 619 | ip_link_is_up()
|
| 620 | {
|
| 621 | ip_link_has_flag "$1" UP
|
| 622 | }
|
| 623 |
|
| 624 | adf_ip_link_set_up()
|
| 625 | {
|
| 626 | local name=$1; shift
|
| 627 |
|
| 628 | if ! ip_link_is_up "$name"; then
|
| 629 | ip link set dev "$name" up && \
|
| 630 | defer ip link set dev "$name" down
|
| 631 | fi
|
| 632 | }
|
| 633 |
|
| 634 | adf_ip_link_set_down()
|
| 635 | {
|
| 636 | local name=$1; shift
|
| 637 |
|
| 638 | if ip_link_is_up "$name"; then
|
| 639 | ip link set dev "$name" down && \
|
| 640 | defer ip link set dev "$name" up
|
| 641 | fi
|
| 642 | }
|
| 643 |
|
| 644 | adf_ip_addr_add()
|
| 645 | {
|
| 646 | local name=$1; shift
|
| 647 |
|
| 648 | ip addr add dev "$name" "$@" && \
|
| 649 | defer ip addr del dev "$name" "$@"
|
| 650 | }
|
| 651 |
|
| 652 | adf_ip_route_add()
|
| 653 | {
|
| 654 | ip route add "$@" && \
|
| 655 | defer ip route del "$@"
|
| 656 | }
|
| 657 |
|
| 658 | adf_bridge_vlan_add()
|
| 659 | {
|
| 660 | bridge vlan add "$@" && \
|
| 661 | defer bridge vlan del "$@"
|
| 662 | }
|
| 663 |
|
| 664 | wait_local_port_listen()
|
| 665 | {
|
| 666 | local listener_ns="${1}"
|
| 667 | local port="${2}"
|
| 668 | local protocol="${3}"
|
| 669 | local pattern
|
| 670 | local i
|
| 671 |
|
| 672 | pattern=":$(printf "%04X" "${port}") "
|
| 673 |
|
| 674 | |
| 675 | [ ${protocol} = "tcp" ] && pattern="${pattern}0A"
|
| 676 | for i in $(seq 10); do
|
| 677 | if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \
|
| 678 | /proc/net/"${protocol}"* | grep -q "${pattern}"; then
|
| 679 | break
|
| 680 | fi
|
| 681 | sleep 0.1
|
| 682 | done
|
| 683 | }
|
| 684 |
|
| 685 | cmd_jq()
|
| 686 | {
|
| 687 | local cmd=$1
|
| 688 | local jq_exp=$2
|
| 689 | local jq_opts=$3
|
| 690 | local ret
|
| 691 | local output
|
| 692 |
|
| 693 | output="$($cmd)"
|
| 694 | |
| 695 | ret=$?
|
| 696 | if [[ $ret -ne 0 ]]; then
|
| 697 | return $ret
|
| 698 | fi
|
| 699 | output=$(echo $output | jq -r $jq_opts "$jq_exp")
|
| 700 | ret=$?
|
| 701 | if [[ $ret -ne 0 ]]; then
|
| 702 | return $ret
|
| 703 | fi
|
| 704 | echo $output
|
| 705 | |
| 706 | [ ! -z "$output" ]
|
| 707 | }
|
| 708 |
|
| 709 | run_on()
|
| 710 | {
|
| 711 | shift; "$@"
|
| 712 | }
|