1#! /bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4. "$(dirname "${0}")/../lib.sh" 5 6readonly KSFT_PASS=0 7readonly KSFT_FAIL=1 8readonly KSFT_SKIP=4 9 10# shellcheck disable=SC2155 # declare and assign separately 11readonly KSFT_TEST="${MPTCP_LIB_KSFT_TEST:-$(basename "${0}" .sh)}" 12 13# These variables are used in some selftests, read-only 14declare -rx MPTCP_LIB_EVENT_CREATED=1 # MPTCP_EVENT_CREATED 15declare -rx MPTCP_LIB_EVENT_ESTABLISHED=2 # MPTCP_EVENT_ESTABLISHED 16declare -rx MPTCP_LIB_EVENT_CLOSED=3 # MPTCP_EVENT_CLOSED 17declare -rx MPTCP_LIB_EVENT_ANNOUNCED=6 # MPTCP_EVENT_ANNOUNCED 18declare -rx MPTCP_LIB_EVENT_REMOVED=7 # MPTCP_EVENT_REMOVED 19declare -rx MPTCP_LIB_EVENT_SUB_ESTABLISHED=10 # MPTCP_EVENT_SUB_ESTABLISHED 20declare -rx MPTCP_LIB_EVENT_SUB_CLOSED=11 # MPTCP_EVENT_SUB_CLOSED 21declare -rx MPTCP_LIB_EVENT_SUB_PRIORITY=13 # MPTCP_EVENT_SUB_PRIORITY 22declare -rx MPTCP_LIB_EVENT_LISTENER_CREATED=15 # MPTCP_EVENT_LISTENER_CREATED 23declare -rx MPTCP_LIB_EVENT_LISTENER_CLOSED=16 # MPTCP_EVENT_LISTENER_CLOSED 24 25declare -rx MPTCP_LIB_AF_INET=2 26declare -rx MPTCP_LIB_AF_INET6=10 27 28MPTCP_LIB_SUBTESTS=() 29MPTCP_LIB_SUBTESTS_DUPLICATED=0 30MPTCP_LIB_SUBTEST_FLAKY=0 31MPTCP_LIB_SUBTESTS_LAST_TS_MS= 32MPTCP_LIB_TEST_COUNTER=0 33MPTCP_LIB_TEST_FORMAT="%02u %-50s" 34MPTCP_LIB_IP_MPTCP=0 35 36# only if supported (or forced) and not disabled, see no-color.org 37if { [ -t 1 ] || [ "${SELFTESTS_MPTCP_LIB_COLOR_FORCE:-}" = "1" ]; } && 38 [ "${NO_COLOR:-}" != "1" ]; then 39 readonly MPTCP_LIB_COLOR_RED="\E[1;31m" 40 readonly MPTCP_LIB_COLOR_GREEN="\E[1;32m" 41 readonly MPTCP_LIB_COLOR_YELLOW="\E[1;33m" 42 readonly MPTCP_LIB_COLOR_BLUE="\E[1;34m" 43 readonly MPTCP_LIB_COLOR_RESET="\E[0m" 44else 45 readonly MPTCP_LIB_COLOR_RED= 46 readonly MPTCP_LIB_COLOR_GREEN= 47 readonly MPTCP_LIB_COLOR_YELLOW= 48 readonly MPTCP_LIB_COLOR_BLUE= 49 readonly MPTCP_LIB_COLOR_RESET= 50fi 51 52# SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY env var can be set not to ignore errors 53# from subtests marked as flaky 54mptcp_lib_override_flaky() { 55 [ "${SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:-}" = 1 ] 56} 57 58mptcp_lib_subtest_is_flaky() { 59 [ "${MPTCP_LIB_SUBTEST_FLAKY}" = 1 ] && ! mptcp_lib_override_flaky 60} 61 62# $1: color, $2: text 63mptcp_lib_print_color() { 64 echo -e "${MPTCP_LIB_START_PRINT:-}${*}${MPTCP_LIB_COLOR_RESET}" 65} 66 67mptcp_lib_print_ok() { 68 mptcp_lib_print_color "${MPTCP_LIB_COLOR_GREEN}${*}" 69} 70 71mptcp_lib_print_warn() { 72 mptcp_lib_print_color "${MPTCP_LIB_COLOR_YELLOW}${*}" 73} 74 75mptcp_lib_print_info() { 76 mptcp_lib_print_color "${MPTCP_LIB_COLOR_BLUE}${*}" 77} 78 79mptcp_lib_print_err() { 80 mptcp_lib_print_color "${MPTCP_LIB_COLOR_RED}${*}" 81} 82 83# shellcheck disable=SC2120 # parameters are optional 84mptcp_lib_pr_ok() { 85 mptcp_lib_print_ok "[ OK ]${1:+ ${*}}" 86} 87 88mptcp_lib_pr_skip() { 89 mptcp_lib_print_warn "[SKIP]${1:+ ${*}}" 90} 91 92mptcp_lib_pr_fail() { 93 local title cmt 94 95 if mptcp_lib_subtest_is_flaky; then 96 title="IGNO" 97 cmt=" (flaky)" 98 else 99 title="FAIL" 100 fi 101 102 mptcp_lib_print_err "[${title}]${cmt}${1:+ ${*}}" 103} 104 105mptcp_lib_pr_info() { 106 mptcp_lib_print_info "INFO: ${*}" 107} 108 109# $1-2: listener/connector ns ; $3 port ; $4-5 listener/connector stat file 110mptcp_lib_pr_err_stats() { 111 local lns="${1}" 112 local cns="${2}" 113 local port="${3}" 114 local lstat="${4}" 115 local cstat="${5}" 116 117 echo -en "${MPTCP_LIB_COLOR_RED}" 118 { 119 printf "\nnetns %s (listener) socket stat for %d:\n" "${lns}" "${port}" 120 ip netns exec "${lns}" ss -Menitam -o "sport = :${port}" 121 cat "${lstat}" 122 123 printf "\nnetns %s (connector) socket stat for %d:\n" "${cns}" "${port}" 124 ip netns exec "${cns}" ss -Menitam -o "dport = :${port}" 125 [ "${lstat}" != "${cstat}" ] && cat "${cstat}" 126 } 1>&2 127 echo -en "${MPTCP_LIB_COLOR_RESET}" 128} 129 130# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all 131# features using the last version of the kernel and the selftests to make sure 132# a test is not being skipped by mistake. 133mptcp_lib_expect_all_features() { 134 [ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ] 135} 136 137# $1: msg 138mptcp_lib_fail_if_expected_feature() { 139 if mptcp_lib_expect_all_features; then 140 echo "ERROR: missing feature: ${*}" 141 exit ${KSFT_FAIL} 142 fi 143 144 return 1 145} 146 147# $1: file 148mptcp_lib_has_file() { 149 local f="${1}" 150 151 if [ -f "${f}" ]; then 152 return 0 153 fi 154 155 mptcp_lib_fail_if_expected_feature "${f} file not found" 156} 157 158mptcp_lib_check_mptcp() { 159 if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then 160 mptcp_lib_pr_skip "MPTCP support is not available" 161 exit ${KSFT_SKIP} 162 fi 163} 164 165mptcp_lib_check_kallsyms() { 166 if ! mptcp_lib_has_file "/proc/kallsyms"; then 167 mptcp_lib_pr_skip "CONFIG_KALLSYMS is missing" 168 exit ${KSFT_SKIP} 169 fi 170} 171 172# Internal: use mptcp_lib_kallsyms_has() instead 173__mptcp_lib_kallsyms_has() { 174 local sym="${1}" 175 176 mptcp_lib_check_kallsyms 177 178 grep -q " ${sym}" /proc/kallsyms 179} 180 181# $1: part of a symbol to look at, add '$' at the end for full name 182mptcp_lib_kallsyms_has() { 183 local sym="${1}" 184 185 if __mptcp_lib_kallsyms_has "${sym}"; then 186 return 0 187 fi 188 189 mptcp_lib_fail_if_expected_feature "${sym} symbol not found" 190} 191 192# $1: part of a symbol to look at, add '$' at the end for full name 193mptcp_lib_kallsyms_doesnt_have() { 194 local sym="${1}" 195 196 if ! __mptcp_lib_kallsyms_has "${sym}"; then 197 return 0 198 fi 199 200 mptcp_lib_fail_if_expected_feature "${sym} symbol has been found" 201} 202 203# !!!AVOID USING THIS!!! 204# Features might not land in the expected version and features can be backported 205# 206# $1: kernel version, e.g. 6.3 207mptcp_lib_kversion_ge() { 208 local exp_maj="${1%.*}" 209 local exp_min="${1#*.}" 210 local v maj min 211 212 # If the kernel has backported features, set this env var to 1: 213 if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then 214 return 0 215 fi 216 217 v=$(uname -r | cut -d'.' -f1,2) 218 maj=${v%.*} 219 min=${v#*.} 220 221 if [ "${maj}" -gt "${exp_maj}" ] || 222 { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then 223 return 0 224 fi 225 226 mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}" 227} 228 229mptcp_lib_subtests_last_ts_reset() { 230 MPTCP_LIB_SUBTESTS_LAST_TS_MS="$(date +%s%3N)" 231} 232mptcp_lib_subtests_last_ts_reset 233 234__mptcp_lib_result_check_duplicated() { 235 local subtest 236 237 for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do 238 if [[ "${subtest}" == *" - ${KSFT_TEST}: ${*%% #*}" ]]; then 239 MPTCP_LIB_SUBTESTS_DUPLICATED=1 240 mptcp_lib_print_err "Duplicated entry: ${*}" 241 break 242 fi 243 done 244} 245 246__mptcp_lib_result_add() { 247 local result="${1}" 248 local time="time=" 249 local ts_prev_ms 250 shift 251 252 local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1)) 253 254 __mptcp_lib_result_check_duplicated "${*}" 255 256 # not to add two '#' 257 [[ "${*}" != *"#"* ]] && time="# ${time}" 258 259 ts_prev_ms="${MPTCP_LIB_SUBTESTS_LAST_TS_MS}" 260 mptcp_lib_subtests_last_ts_reset 261 time+="$((MPTCP_LIB_SUBTESTS_LAST_TS_MS - ts_prev_ms))ms" 262 263 MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*} ${time}") 264} 265 266# $1: test name 267mptcp_lib_result_pass() { 268 __mptcp_lib_result_add "ok" "${1}" 269} 270 271# $1: test name 272mptcp_lib_result_fail() { 273 if mptcp_lib_subtest_is_flaky; then 274 # It might sound better to use 'not ok # TODO' or 'ok # SKIP', 275 # but some CIs don't understand 'TODO' and treat SKIP as errors. 276 __mptcp_lib_result_add "ok" "${1} # IGNORE Flaky" 277 else 278 __mptcp_lib_result_add "not ok" "${1}" 279 fi 280} 281 282# $1: test name 283mptcp_lib_result_skip() { 284 __mptcp_lib_result_add "ok" "${1} # SKIP" 285} 286 287# $1: result code ; $2: test name 288mptcp_lib_result_code() { 289 local ret="${1}" 290 local name="${2}" 291 292 case "${ret}" in 293 "${KSFT_PASS}") 294 mptcp_lib_result_pass "${name}" 295 ;; 296 "${KSFT_FAIL}") 297 mptcp_lib_result_fail "${name}" 298 ;; 299 "${KSFT_SKIP}") 300 mptcp_lib_result_skip "${name}" 301 ;; 302 *) 303 echo "ERROR: wrong result code: ${ret}" 304 exit ${KSFT_FAIL} 305 ;; 306 esac 307} 308 309mptcp_lib_result_print_all_tap() { 310 local subtest 311 312 if [ ${#MPTCP_LIB_SUBTESTS[@]} -eq 0 ] || 313 [ "${SELFTESTS_MPTCP_LIB_NO_TAP:-}" = "1" ]; then 314 return 315 fi 316 317 printf "\nTAP version 13\n" 318 printf "1..%d\n" "${#MPTCP_LIB_SUBTESTS[@]}" 319 320 for subtest in "${MPTCP_LIB_SUBTESTS[@]}"; do 321 printf "%s\n" "${subtest}" 322 done 323 324 if [ "${MPTCP_LIB_SUBTESTS_DUPLICATED}" = 1 ] && 325 mptcp_lib_expect_all_features; then 326 mptcp_lib_print_err "Duplicated test entries" 327 exit ${KSFT_FAIL} 328 fi 329} 330 331# get the value of keyword $1 in the line marked by keyword $2 332mptcp_lib_get_info_value() { 333 grep "${2}" 2>/dev/null | 334 sed -n 's/.*\('"${1}"':\)\([0-9a-f:.]*\).*$/\2/p;q' 335 # the ';q' at the end limits to the first matched entry. 336} 337 338# $1: info name ; $2: evts_ns ; [$3: event type; [$4: addr]] 339mptcp_lib_evts_get_info() { 340 grep "${4:-}" "${2}" 2>/dev/null | 341 mptcp_lib_get_info_value "${1}" "^type:${3:-1}," 342} 343 344# $1: PID 345mptcp_lib_kill_wait() { 346 [ "${1}" -eq 0 ] && return 0 347 348 kill -SIGUSR1 "${1}" > /dev/null 2>&1 349 kill "${1}" > /dev/null 2>&1 350 wait "${1}" 2>/dev/null 351} 352 353# $1: PID 354mptcp_lib_pid_list_children() { 355 local curr="${1}" 356 # evoke 'ps' only once 357 local pids="${2:-"$(ps o pid,ppid)"}" 358 359 echo "${curr}" 360 361 local pid 362 for pid in $(echo "${pids}" | awk "\$2 == ${curr} { print \$1 }"); do 363 mptcp_lib_pid_list_children "${pid}" "${pids}" 364 done 365} 366 367# $1: PID 368mptcp_lib_kill_group_wait() { 369 # Some users might not have procps-ng: cannot use "kill -- -PID" 370 mptcp_lib_pid_list_children "${1}" | xargs -r kill &>/dev/null 371 wait "${1}" 2>/dev/null 372} 373 374# $1: IP address 375mptcp_lib_is_v6() { 376 [ -z "${1##*:*}" ] 377} 378 379# $1: ns, $2: MIB counter 380mptcp_lib_get_counter() { 381 local ns="${1}" 382 local counter="${2}" 383 local count 384 385 count=$(ip netns exec "${ns}" nstat -asz "${counter}" | 386 awk 'NR==1 {next} {print $2}') 387 if [ -z "${count}" ]; then 388 mptcp_lib_fail_if_expected_feature "${counter} counter" 389 return 1 390 fi 391 392 echo "${count}" 393} 394 395mptcp_lib_make_file() { 396 local name="${1}" 397 local bs="${2}" 398 local size="${3}" 399 400 dd if=/dev/urandom of="${name}" bs="${bs}" count="${size}" 2> /dev/null 401 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "${name}" 402} 403 404# $1: file 405mptcp_lib_print_file_err() { 406 ls -l "${1}" 1>&2 407 echo "Trailing bytes are: " 408 tail -c 32 "${1}" | od -x | head -n2 409} 410 411# $1: input file ; $2: output file ; $3: what kind of file 412mptcp_lib_check_transfer() { 413 local in="${1}" 414 local out="${2}" 415 local what="${3}" 416 417 if ! cmp "$in" "$out" > /dev/null 2>&1; then 418 mptcp_lib_pr_fail "$what does not match (in, out):" 419 mptcp_lib_print_file_err "$in" 420 mptcp_lib_print_file_err "$out" 421 422 return 1 423 fi 424 425 return 0 426} 427 428# $1: ns, $2: port 429mptcp_lib_wait_local_port_listen() { 430 wait_local_port_listen "${@}" "tcp" 431} 432 433mptcp_lib_check_output() { 434 local err="${1}" 435 local cmd="${2}" 436 local expected="${3}" 437 local cmd_ret=0 438 local out 439 440 if ! out=$(${cmd} 2>"${err}"); then 441 cmd_ret=${?} 442 fi 443 444 if [ ${cmd_ret} -ne 0 ]; then 445 mptcp_lib_pr_fail "command execution '${cmd}' stderr" 446 cat "${err}" 447 return 2 448 elif [ "${out}" = "${expected}" ]; then 449 return 0 450 else 451 mptcp_lib_pr_fail "expected '${expected}' got '${out}'" 452 return 1 453 fi 454} 455 456mptcp_lib_check_tools() { 457 local tool 458 459 for tool in "${@}"; do 460 case "${tool}" in 461 "ip") 462 if ! ip -Version &> /dev/null; then 463 mptcp_lib_pr_skip "Could not run test without ip tool" 464 exit ${KSFT_SKIP} 465 fi 466 ;; 467 "tc") 468 if ! tc -help &> /dev/null; then 469 mptcp_lib_pr_skip "Could not run test without tc tool" 470 exit ${KSFT_SKIP} 471 fi 472 ;; 473 "ss") 474 if ! ss -h | grep -q MPTCP; then 475 mptcp_lib_pr_skip "ss tool does not support MPTCP" 476 exit ${KSFT_SKIP} 477 fi 478 ;; 479 "iptables"* | "ip6tables"*) 480 if ! "${tool}" -V &> /dev/null; then 481 mptcp_lib_pr_skip "Could not run all tests without ${tool}" 482 exit ${KSFT_SKIP} 483 fi 484 ;; 485 *) 486 mptcp_lib_pr_fail "Internal error: unsupported tool: ${tool}" 487 exit ${KSFT_FAIL} 488 ;; 489 esac 490 done 491} 492 493mptcp_lib_ns_init() { 494 if ! setup_ns "${@}"; then 495 mptcp_lib_pr_fail "Failed to setup namespaces ${*}" 496 exit ${KSFT_FAIL} 497 fi 498 499 local netns 500 for netns in "${@}"; do 501 ip netns exec "${!netns}" sysctl -q net.mptcp.enabled=1 502 done 503} 504 505mptcp_lib_ns_exit() { 506 cleanup_ns "${@}" 507 508 local netns 509 for netns in "${@}"; do 510 rm -f /tmp/"${netns}".{nstat,out} 511 done 512} 513 514mptcp_lib_events() { 515 local ns="${1}" 516 local evts="${2}" 517 declare -n pid="${3}" 518 519 :>"${evts}" 520 521 mptcp_lib_kill_wait "${pid:-0}" 522 ip netns exec "${ns}" ./pm_nl_ctl events >> "${evts}" 2>&1 & 523 pid=$! 524} 525 526mptcp_lib_print_title() { 527 : "${MPTCP_LIB_TEST_COUNTER:?}" 528 : "${MPTCP_LIB_TEST_FORMAT:?}" 529 530 # shellcheck disable=SC2059 # the format is in a variable 531 printf "${MPTCP_LIB_TEST_FORMAT}" "$((++MPTCP_LIB_TEST_COUNTER))" "${*}" 532} 533 534# $1: var name ; $2: prev ret 535mptcp_lib_check_expected_one() { 536 local var="${1}" 537 local exp="e_${var}" 538 local prev_ret="${2}" 539 540 if [ "${!var}" = "${!exp}" ]; then 541 return 0 542 fi 543 544 if [ "${prev_ret}" = "0" ]; then 545 mptcp_lib_pr_fail 546 fi 547 548 mptcp_lib_print_err "Expected value for '${var}': '${!exp}', got '${!var}'." 549 return 1 550} 551 552# $@: all var names to check 553mptcp_lib_check_expected() { 554 local rc=0 555 local var 556 557 for var in "${@}"; do 558 mptcp_lib_check_expected_one "${var}" "${rc}" || rc=1 559 done 560 561 return "${rc}" 562} 563 564# shellcheck disable=SC2034 # Some variables are used below but indirectly 565mptcp_lib_verify_listener_events() { 566 local evt=${1} 567 local e_type=${2} 568 local e_family=${3} 569 local e_saddr=${4} 570 local e_sport=${5} 571 local type 572 local family 573 local saddr 574 local sport 575 local rc=0 576 577 type=$(mptcp_lib_evts_get_info type "${evt}" "${e_type}") 578 family=$(mptcp_lib_evts_get_info family "${evt}" "${e_type}") 579 if [ "${family}" ] && [ "${family}" = "${AF_INET6}" ]; then 580 saddr=$(mptcp_lib_evts_get_info saddr6 "${evt}" "${e_type}") 581 else 582 saddr=$(mptcp_lib_evts_get_info saddr4 "${evt}" "${e_type}") 583 fi 584 sport=$(mptcp_lib_evts_get_info sport "${evt}" "${e_type}") 585 586 mptcp_lib_check_expected "type" "family" "saddr" "sport" || rc="${?}" 587 return "${rc}" 588} 589 590mptcp_lib_set_ip_mptcp() { 591 MPTCP_LIB_IP_MPTCP=1 592} 593 594mptcp_lib_is_ip_mptcp() { 595 [ "${MPTCP_LIB_IP_MPTCP}" = "1" ] 596} 597 598# format: <id>,<ip>,<flags>,<dev> 599mptcp_lib_pm_nl_format_endpoints() { 600 local entry id ip flags dev port 601 602 for entry in "${@}"; do 603 IFS=, read -r id ip flags dev port <<< "${entry}" 604 if mptcp_lib_is_ip_mptcp; then 605 echo -n "${ip}" 606 [ -n "${port}" ] && echo -n " port ${port}" 607 echo -n " id ${id}" 608 [ -n "${flags}" ] && echo -n " ${flags}" 609 [ -n "${dev}" ] && echo -n " dev ${dev}" 610 echo " " # always a space at the end 611 else 612 echo -n "id ${id}" 613 echo -n " flags ${flags//" "/","}" 614 [ -n "${dev}" ] && echo -n " dev ${dev}" 615 echo -n " ${ip}" 616 [ -n "${port}" ] && echo -n " ${port}" 617 echo "" 618 fi 619 done 620} 621 622mptcp_lib_pm_nl_get_endpoint() { 623 local ns=${1} 624 local id=${2} 625 626 if mptcp_lib_is_ip_mptcp; then 627 ip -n "${ns}" mptcp endpoint show id "${id}" 628 else 629 ip netns exec "${ns}" ./pm_nl_ctl get "${id}" 630 fi 631} 632 633mptcp_lib_pm_nl_set_limits() { 634 local ns=${1} 635 local addrs=${2} 636 local subflows=${3} 637 638 if mptcp_lib_is_ip_mptcp; then 639 ip -n "${ns}" mptcp limits set add_addr_accepted "${addrs}" subflows "${subflows}" 640 else 641 ip netns exec "${ns}" ./pm_nl_ctl limits "${addrs}" "${subflows}" 642 fi 643} 644 645mptcp_lib_pm_nl_add_endpoint() { 646 local ns=${1} 647 local addr=${2} 648 local flags dev id port 649 local nr=2 650 651 local p 652 for p in "${@}"; do 653 case "${p}" in 654 "flags" | "dev" | "id" | "port") 655 eval "${p}"=\$"${nr}" 656 ;; 657 esac 658 659 nr=$((nr + 1)) 660 done 661 662 if mptcp_lib_is_ip_mptcp; then 663 # shellcheck disable=SC2086 # blanks in flags, no double quote 664 ip -n "${ns}" mptcp endpoint add "${addr}" ${flags//","/" "} \ 665 ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"} 666 else 667 ip netns exec "${ns}" ./pm_nl_ctl add "${addr}" ${flags:+flags "${flags}"} \ 668 ${dev:+dev "${dev}"} ${id:+id "${id}"} ${port:+port "${port}"} 669 fi 670} 671 672mptcp_lib_pm_nl_del_endpoint() { 673 local ns=${1} 674 local id=${2} 675 local addr=${3} 676 677 if mptcp_lib_is_ip_mptcp; then 678 [ "${id}" -ne 0 ] && addr='' 679 ip -n "${ns}" mptcp endpoint delete id "${id}" ${addr:+"${addr}"} 680 else 681 ip netns exec "${ns}" ./pm_nl_ctl del "${id}" "${addr}" 682 fi 683} 684 685mptcp_lib_pm_nl_flush_endpoint() { 686 local ns=${1} 687 688 if mptcp_lib_is_ip_mptcp; then 689 ip -n "${ns}" mptcp endpoint flush 690 else 691 ip netns exec "${ns}" ./pm_nl_ctl flush 692 fi 693} 694 695mptcp_lib_pm_nl_show_endpoints() { 696 local ns=${1} 697 698 if mptcp_lib_is_ip_mptcp; then 699 ip -n "${ns}" mptcp endpoint show 700 else 701 ip netns exec "${ns}" ./pm_nl_ctl dump 702 fi 703} 704 705mptcp_lib_pm_nl_change_endpoint() { 706 local ns=${1} 707 local id=${2} 708 local flags=${3} 709 710 if mptcp_lib_is_ip_mptcp; then 711 # shellcheck disable=SC2086 # blanks in flags, no double quote 712 ip -n "${ns}" mptcp endpoint change id "${id}" ${flags//","/" "} 713 else 714 ip netns exec "${ns}" ./pm_nl_ctl set id "${id}" flags "${flags}" 715 fi 716} 717