1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright (C) 2016 Intel Corporation 3# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES 4# All rights reserved. 5# 6 7[[ $(uname -s) == FreeBSD ]] && return 0 8 9NVMF_PORT=4420 10NVMF_SECOND_PORT=4421 11NVMF_THIRD_PORT=4422 12NVMF_IP_PREFIX="192.168.100" 13NVMF_IP_LEAST_ADDR=8 14NVMF_TCP_IP_ADDRESS="127.0.0.1" 15NVMF_TRANSPORT_OPTS="" 16NVMF_SERIAL=SPDKISFASTANDAWESOME 17NVME_HOSTNQN=$(nvme gen-hostnqn) 18NVME_HOSTID=${NVME_HOSTNQN##*:} 19NVME_HOST=("--hostnqn=$NVME_HOSTNQN" "--hostid=$NVME_HOSTID") 20NVME_CONNECT="nvme connect" 21NET_TYPE=${NET_TYPE:-phy-fallback} 22NVME_SUBNQN=nqn.2016-06.io.spdk:testnqn 23 24function build_nvmf_app_args() { 25 if [ $SPDK_RUN_NON_ROOT -eq 1 ]; then 26 # We assume that test script is started from sudo 27 NVMF_APP=(sudo -E -u $SUDO_USER "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" "${NVMF_APP[@]}") 28 fi 29 NVMF_APP+=(-i "$NVMF_APP_SHM_ID" -e 0xFFFF) 30 31 NVMF_APP+=("${NO_HUGE[@]}") 32 33 if [ -n "$SPDK_HUGE_DIR" ]; then 34 NVMF_APP+=(--huge-dir "$SPDK_HUGE_DIR") 35 elif [ $SPDK_RUN_NON_ROOT -eq 1 ]; then 36 echo "In non-root test mode you have to set SPDK_HUGE_DIR variable." >&2 37 echo "For example:" >&2 38 echo "sudo mkdir /mnt/spdk_hugetlbfs" >&2 39 echo "sudo chown ${SUDO_USER}: /mnt/spdk_hugetlbfs" >&2 40 echo "export SPDK_HUGE_DIR=/mnt/spdk_hugetlbfs" >&2 41 return 1 42 fi 43} 44 45source "$rootdir/scripts/common.sh" 46 47: ${NVMF_APP_SHM_ID="0"} 48export NVMF_APP_SHM_ID 49build_nvmf_app_args 50 51have_pci_nics=0 52 53function rxe_cfg() { 54 "$rootdir/scripts/rxe_cfg_small.sh" "$@" 55} 56 57function load_ib_rdma_modules() { 58 if [ $(uname) != Linux ]; then 59 return 0 60 fi 61 62 modprobe ib_cm 63 modprobe ib_core 64 modprobe ib_umad 65 modprobe ib_uverbs 66 modprobe iw_cm 67 modprobe rdma_cm 68 modprobe rdma_ucm 69} 70 71function allocate_nic_ips() { 72 ((count = NVMF_IP_LEAST_ADDR)) 73 for nic_name in $(get_rdma_if_list); do 74 ip="$(get_ip_address $nic_name)" 75 if [[ -z $ip ]]; then 76 ip addr add $NVMF_IP_PREFIX.$count/24 dev $nic_name 77 ip link set $nic_name up 78 ((count = count + 1)) 79 fi 80 # dump configuration for debug log 81 ip addr show $nic_name 82 done 83} 84 85function get_available_rdma_ips() { 86 for nic_name in $(get_rdma_if_list); do 87 get_ip_address $nic_name 88 done 89} 90 91function get_rdma_if_list() { 92 local net_dev rxe_net_dev rxe_net_devs 93 94 mapfile -t rxe_net_devs < <(rxe_cfg rxe-net) 95 96 if ((${#net_devs[@]} == 0)); then 97 return 1 98 fi 99 100 # Pick only these devices which were found during gather_supported_nvmf_pci_devs() run 101 for net_dev in "${net_devs[@]}"; do 102 for rxe_net_dev in "${rxe_net_devs[@]}"; do 103 if [[ $net_dev == "$rxe_net_dev" ]]; then 104 echo "$net_dev" 105 continue 2 106 fi 107 done 108 done 109} 110 111function get_ip_address() { 112 interface=$1 113 ip -o -4 addr show $interface | awk '{print $4}' | cut -d"/" -f1 114} 115 116function nvmfcleanup() { 117 sync 118 119 if [ "$TEST_TRANSPORT" == "tcp" ] || [ "$TEST_TRANSPORT" == "rdma" ]; then 120 set +e 121 for i in {1..20}; do 122 modprobe -v -r nvme-$TEST_TRANSPORT 123 if modprobe -v -r nvme-fabrics; then 124 set -e 125 return 0 126 fi 127 sleep 1 128 done 129 set -e 130 131 # So far unable to remove the kernel modules. Try 132 # one more time and let it fail. 133 # Allow the transport module to fail for now. See Jim's comment 134 # about the nvme-tcp module below. 135 modprobe -v -r nvme-$TEST_TRANSPORT || true 136 modprobe -v -r nvme-fabrics 137 fi 138} 139 140function nvmf_veth_init() { 141 NVMF_FIRST_INITIATOR_IP=10.0.0.1 142 NVMF_SECOND_INITIATOR_IP=10.0.0.2 143 NVMF_FIRST_TARGET_IP=10.0.0.3 144 NVMF_SECOND_TARGET_IP=10.0.0.4 145 NVMF_INITIATOR_IP=$NVMF_FIRST_INITIATOR_IP 146 NVMF_BRIDGE="nvmf_br" 147 NVMF_INITIATOR_INTERFACE="nvmf_init_if" 148 NVMF_INITIATOR_INTERFACE2="nvmf_init_if2" 149 NVMF_INITIATOR_BRIDGE="nvmf_init_br" 150 NVMF_INITIATOR_BRIDGE2="nvmf_init_br2" 151 NVMF_TARGET_NAMESPACE="nvmf_tgt_ns_spdk" 152 NVMF_TARGET_NS_CMD=(ip netns exec "$NVMF_TARGET_NAMESPACE") 153 NVMF_TARGET_INTERFACE="nvmf_tgt_if" 154 NVMF_TARGET_INTERFACE2="nvmf_tgt_if2" 155 NVMF_TARGET_BRIDGE="nvmf_tgt_br" 156 NVMF_TARGET_BRIDGE2="nvmf_tgt_br2" 157 158 ip link set $NVMF_INITIATOR_BRIDGE nomaster || true 159 ip link set $NVMF_INITIATOR_BRIDGE2 nomaster || true 160 ip link set $NVMF_TARGET_BRIDGE nomaster || true 161 ip link set $NVMF_TARGET_BRIDGE2 nomaster || true 162 ip link set $NVMF_INITIATOR_BRIDGE down || true 163 ip link set $NVMF_INITIATOR_BRIDGE2 down || true 164 ip link set $NVMF_TARGET_BRIDGE down || true 165 ip link set $NVMF_TARGET_BRIDGE2 down || true 166 ip link delete $NVMF_BRIDGE type bridge || true 167 ip link delete $NVMF_INITIATOR_INTERFACE || true 168 ip link delete $NVMF_INITIATOR_INTERFACE2 || true 169 "${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE || true 170 "${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE2 || true 171 172 # Create network namespace 173 ip netns add $NVMF_TARGET_NAMESPACE 174 175 # Create veth (Virtual ethernet) interface pairs 176 ip link add $NVMF_INITIATOR_INTERFACE type veth peer name $NVMF_INITIATOR_BRIDGE 177 ip link add $NVMF_INITIATOR_INTERFACE2 type veth peer name $NVMF_INITIATOR_BRIDGE2 178 ip link add $NVMF_TARGET_INTERFACE type veth peer name $NVMF_TARGET_BRIDGE 179 ip link add $NVMF_TARGET_INTERFACE2 type veth peer name $NVMF_TARGET_BRIDGE2 180 181 # Associate veth interface pairs with network namespace 182 ip link set $NVMF_TARGET_INTERFACE netns $NVMF_TARGET_NAMESPACE 183 ip link set $NVMF_TARGET_INTERFACE2 netns $NVMF_TARGET_NAMESPACE 184 185 # Allocate IP addresses 186 ip addr add $NVMF_FIRST_INITIATOR_IP/24 dev $NVMF_INITIATOR_INTERFACE 187 ip addr add $NVMF_SECOND_INITIATOR_IP/24 dev $NVMF_INITIATOR_INTERFACE2 188 "${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_FIRST_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE 189 "${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_SECOND_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE2 190 191 # Link up veth interfaces 192 ip link set $NVMF_INITIATOR_INTERFACE up 193 ip link set $NVMF_INITIATOR_INTERFACE2 up 194 ip link set $NVMF_INITIATOR_BRIDGE up 195 ip link set $NVMF_INITIATOR_BRIDGE2 up 196 ip link set $NVMF_TARGET_BRIDGE up 197 ip link set $NVMF_TARGET_BRIDGE2 up 198 "${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE up 199 "${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE2 up 200 "${NVMF_TARGET_NS_CMD[@]}" ip link set lo up 201 202 # Create a bridge 203 ip link add $NVMF_BRIDGE type bridge 204 ip link set $NVMF_BRIDGE up 205 206 # Add veth interfaces to the bridge 207 ip link set $NVMF_INITIATOR_BRIDGE master $NVMF_BRIDGE 208 ip link set $NVMF_INITIATOR_BRIDGE2 master $NVMF_BRIDGE 209 ip link set $NVMF_TARGET_BRIDGE master $NVMF_BRIDGE 210 ip link set $NVMF_TARGET_BRIDGE2 master $NVMF_BRIDGE 211 212 # Accept connections from veth interface 213 ipts -I INPUT 1 -i $NVMF_INITIATOR_INTERFACE -p tcp --dport $NVMF_PORT -j ACCEPT 214 ipts -I INPUT 1 -i $NVMF_INITIATOR_INTERFACE2 -p tcp --dport $NVMF_PORT -j ACCEPT 215 ipts -A FORWARD -i $NVMF_BRIDGE -o $NVMF_BRIDGE -j ACCEPT 216 217 # Verify connectivity 218 ping -c 1 $NVMF_FIRST_TARGET_IP 219 ping -c 1 $NVMF_SECOND_TARGET_IP 220 "${NVMF_TARGET_NS_CMD[@]}" ping -c 1 $NVMF_FIRST_INITIATOR_IP 221 "${NVMF_TARGET_NS_CMD[@]}" ping -c 1 $NVMF_SECOND_INITIATOR_IP 222 223 NVMF_APP=("${NVMF_TARGET_NS_CMD[@]}" "${NVMF_APP[@]}") 224} 225 226function nvmf_veth_fini() { 227 # Cleanup bridge, veth interfaces, and network namespace 228 # Note: removing one veth removes the pair 229 ip link set $NVMF_INITIATOR_BRIDGE nomaster 230 ip link set $NVMF_INITIATOR_BRIDGE2 nomaster 231 ip link set $NVMF_TARGET_BRIDGE nomaster 232 ip link set $NVMF_TARGET_BRIDGE2 nomaster 233 ip link set $NVMF_INITIATOR_BRIDGE down 234 ip link set $NVMF_INITIATOR_BRIDGE2 down 235 ip link set $NVMF_TARGET_BRIDGE down 236 ip link set $NVMF_TARGET_BRIDGE2 down 237 ip link delete $NVMF_BRIDGE type bridge 238 ip link delete $NVMF_INITIATOR_INTERFACE 239 ip link delete $NVMF_INITIATOR_INTERFACE2 240 "${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE 241 "${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE2 242 remove_spdk_ns 243} 244 245function nvmf_tcp_init() { 246 NVMF_FIRST_INITIATOR_IP=10.0.0.1 247 NVMF_FIRST_TARGET_IP=10.0.0.2 248 NVMF_INITIATOR_IP=$NVMF_FIRST_INITIATOR_IP 249 TCP_INTERFACE_LIST=("${net_devs[@]}") 250 251 # We need two net devs at minimum 252 ((${#TCP_INTERFACE_LIST[@]} > 1)) 253 254 NVMF_TARGET_INTERFACE=${TCP_INTERFACE_LIST[0]} 255 NVMF_INITIATOR_INTERFACE=${TCP_INTERFACE_LIST[1]} 256 257 # Skip case nvmf_multipath in nvmf_tcp_init(), it will be covered by nvmf_veth_init(). 258 NVMF_SECOND_TARGET_IP="" 259 NVMF_SECOND_INITIATOR_IP="" 260 261 NVMF_TARGET_NAMESPACE="${NVMF_TARGET_INTERFACE}_ns_spdk" 262 NVMF_TARGET_NS_CMD=(ip netns exec "$NVMF_TARGET_NAMESPACE") 263 ip -4 addr flush $NVMF_TARGET_INTERFACE || true 264 ip -4 addr flush $NVMF_INITIATOR_INTERFACE || true 265 266 # Create network namespace 267 ip netns add $NVMF_TARGET_NAMESPACE 268 269 # Associate phy interface pairs with network namespace 270 ip link set $NVMF_TARGET_INTERFACE netns $NVMF_TARGET_NAMESPACE 271 272 # Allocate IP addresses 273 ip addr add $NVMF_INITIATOR_IP/24 dev $NVMF_INITIATOR_INTERFACE 274 "${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_FIRST_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE 275 276 # Link up phy interfaces 277 ip link set $NVMF_INITIATOR_INTERFACE up 278 279 "${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE up 280 "${NVMF_TARGET_NS_CMD[@]}" ip link set lo up 281 282 # Accept connections from phy interface 283 ipts -I INPUT 1 -i $NVMF_INITIATOR_INTERFACE -p tcp --dport $NVMF_PORT -j ACCEPT 284 285 # Verify connectivity 286 ping -c 1 $NVMF_FIRST_TARGET_IP 287 "${NVMF_TARGET_NS_CMD[@]}" ping -c 1 $NVMF_INITIATOR_IP 288 289 NVMF_APP=("${NVMF_TARGET_NS_CMD[@]}" "${NVMF_APP[@]}") 290} 291 292function nvmf_tcp_fini() { 293 iptr 294 if [[ "$NVMF_TARGET_NAMESPACE" == "nvmf_tgt_ns_spdk" ]]; then 295 nvmf_veth_fini 296 return 0 297 fi 298 remove_spdk_ns 299 ip -4 addr flush $NVMF_INITIATOR_INTERFACE || : 300} 301 302function gather_supported_nvmf_pci_devs() { 303 # Go through the entire pci bus and gather all ethernet controllers we support for the nvmf tests. 304 # Focus on the hardware that's currently being tested by the CI. 305 xtrace_disable 306 cache_pci_bus_sysfs 307 xtrace_restore 308 309 local intel=0x8086 mellanox=0x15b3 pci net_dev 310 311 local -a pci_devs=() 312 local -a pci_net_devs=() 313 local -A pci_drivers=() 314 315 local -ga net_devs=() 316 local -ga e810=() 317 local -ga x722=() 318 local -ga mlx=() 319 320 # E810-XXV 321 e810+=(${pci_bus_cache["$intel:0x1592"]}) 322 e810+=(${pci_bus_cache["$intel:0x159b"]}) 323 # X722 10G 324 x722+=(${pci_bus_cache["$intel:0x37d2"]}) 325 # BlueField 3 326 mlx+=(${pci_bus_cache["$mellanox:0xa2dc"]}) 327 # ConnectX-7 328 mlx+=(${pci_bus_cache["$mellanox:0x1021"]}) 329 # BlueField 2 330 mlx+=(${pci_bus_cache["$mellanox:0xa2d6"]}) 331 # ConnectX-6 Dx 332 mlx+=(${pci_bus_cache["$mellanox:0x101d"]}) 333 # ConnectX-5 334 mlx+=(${pci_bus_cache["$mellanox:0x1017"]}) 335 mlx+=(${pci_bus_cache["$mellanox:0x1019"]}) 336 # ConnectX-4 337 mlx+=(${pci_bus_cache["$mellanox:0x1015"]}) 338 mlx+=(${pci_bus_cache["$mellanox:0x1013"]}) 339 340 pci_devs+=("${e810[@]}") 341 if [[ $TEST_TRANSPORT == rdma ]]; then 342 pci_devs+=("${x722[@]}") 343 pci_devs+=("${mlx[@]}") 344 fi 345 346 # Try to respect what CI wants to test and override pci_devs[] 347 if [[ $SPDK_TEST_NVMF_NICS == mlx5 ]]; then 348 pci_devs=("${mlx[@]}") 349 elif [[ $SPDK_TEST_NVMF_NICS == e810 ]]; then 350 pci_devs=("${e810[@]}") 351 elif [[ $SPDK_TEST_NVMF_NICS == x722 ]]; then 352 pci_devs=("${x722[@]}") 353 fi 354 355 if ((${#pci_devs[@]} == 0)); then 356 return 1 357 fi 358 359 # Load proper kernel modules if necessary 360 for pci in "${pci_devs[@]}"; do 361 echo "Found $pci (${pci_ids_vendor["$pci"]} - ${pci_ids_device["$pci"]})" 362 if [[ ${pci_mod_resolved["$pci"]} == unknown ]]; then 363 echo "Unresolved modalias for $pci (${pci_mod_driver["$pci"]}). Driver not installed|builtin?" 364 continue 365 fi 366 if [[ ${pci_bus_driver["$pci"]} == unbound ]]; then 367 echo "$pci not bound, needs ${pci_mod_resolved["$pci"]}" 368 pci_drivers["${pci_mod_resolved["$pci"]}"]=1 369 fi 370 if [[ ${pci_ids_device["$pci"]} == "0x1017" ]] \ 371 || [[ ${pci_ids_device["$pci"]} == "0x1019" ]] \ 372 || [[ $TEST_TRANSPORT == rdma ]]; then 373 # Reduce maximum number of queues when connecting with 374 # ConnectX-5 NICs. When using host systems with nproc > 64 375 # connecting with default options (where default equals to 376 # number of host online CPUs) creating all IO queues 377 # takes too much time and results in keep-alive timeout. 378 # See: 379 # https://github.com/spdk/spdk/issues/2772 380 # 0x1017 - MT27800 Family ConnectX-5 381 # 0x1019 - MT28800 Family ConnectX-5 Ex 382 NVME_CONNECT="nvme connect -i 15" 383 fi 384 done 385 386 if ((${#pci_drivers[@]} > 0)); then 387 echo "Loading kernel modules: ${!pci_drivers[*]}" 388 modprobe -a "${!pci_drivers[@]}" 389 fi 390 391 # E810 cards also need irdma driver to be around. 392 if [[ $SPDK_TEST_NVMF_NICS == e810 && $TEST_TRANSPORT == rdma ]]; then 393 if [[ -e /sys/module/irdma/parameters/roce_ena ]]; then 394 # Our tests don't play well with iWARP protocol. Make sure we use RoCEv2 instead. 395 (($(< /sys/module/irdma/parameters/roce_ena) != 1)) && modprobe -r irdma 396 fi 397 modinfo irdma && modprobe irdma roce_ena=1 398 fi > /dev/null 399 400 # All devices detected, kernel modules loaded. Now look under net class to see if there 401 # are any net devices bound to the controllers. 402 for pci in "${pci_devs[@]}"; do 403 pci_net_devs=("/sys/bus/pci/devices/$pci/net/"*) 404 405 # Check if available devices are in proper operational state. If not, remove them from the main list. 406 # This check is valid for TCP only since for RDMA we use infiniband which don't rely on actual UP 407 # state of the device. 408 if [[ $TEST_TRANSPORT == tcp ]]; then 409 for net_dev in "${!pci_net_devs[@]}"; do 410 [[ $(< "${pci_net_devs[net_dev]}/operstate") == up ]] || unset -v "pci_net_devs[net_dev]" 411 done 412 fi 413 414 if ((${#pci_net_devs[@]} == 0)); then 415 echo "No operational net devices associated with $pci" 416 continue 417 fi 418 419 pci_net_devs=("${pci_net_devs[@]##*/}") 420 echo "Found net devices under $pci: ${pci_net_devs[*]}" 421 net_devs+=("${pci_net_devs[@]}") 422 done 423 424 if ((${#net_devs[@]} == 0)); then 425 return 1 426 fi 427} 428 429prepare_net_devs() { 430 local -g is_hw=no 431 432 remove_spdk_ns 433 434 [[ $NET_TYPE != virt ]] && gather_supported_nvmf_pci_devs && is_hw=yes 435 436 if [[ $is_hw == yes ]]; then 437 if [[ $TEST_TRANSPORT == tcp ]]; then 438 nvmf_tcp_init 439 elif [[ $TEST_TRANSPORT == rdma ]]; then 440 rdma_device_init 441 fi 442 return 0 443 elif [[ $NET_TYPE == phy ]]; then 444 echo "ERROR: No supported devices were found, cannot run the $TEST_TRANSPORT test" 445 return 1 446 elif [[ $NET_TYPE == phy-fallback ]]; then 447 echo "WARNING: No supported devices were found, fallback requested for $TEST_TRANSPORT test" 448 fi 449 450 # NET_TYPE == virt or phy-fallback 451 if [[ $TEST_TRANSPORT == tcp ]]; then 452 nvmf_veth_init 453 return 0 454 fi 455 456 echo "ERROR: virt and fallback setup is not supported for $TEST_TRANSPORT" 457 return 1 458} 459 460function nvmftestinit() { 461 if [ -z $TEST_TRANSPORT ]; then 462 echo "transport not specified - use --transport= to specify" 463 return 1 464 fi 465 466 trap 'nvmftestfini' SIGINT SIGTERM EXIT 467 468 prepare_net_devs 469 470 if [ "$TEST_MODE" == "iso" ]; then 471 $rootdir/scripts/setup.sh 472 fi 473 474 NVMF_TRANSPORT_OPTS="-t $TEST_TRANSPORT" 475 if [[ "$TEST_TRANSPORT" == "rdma" ]]; then 476 RDMA_IP_LIST=$(get_available_rdma_ips) 477 NVMF_FIRST_TARGET_IP=$(echo "$RDMA_IP_LIST" | head -n 1) 478 NVMF_SECOND_TARGET_IP=$(echo "$RDMA_IP_LIST" | tail -n +2 | head -n 1) 479 if [ -z $NVMF_FIRST_TARGET_IP ]; then 480 echo "no RDMA NIC for nvmf test" 481 exit 1 482 fi 483 NVMF_TRANSPORT_OPTS="$NVMF_TRANSPORT_OPTS --num-shared-buffers 1024" 484 elif [[ "$TEST_TRANSPORT" == "tcp" ]]; then 485 NVMF_TRANSPORT_OPTS="$NVMF_TRANSPORT_OPTS -o" 486 fi 487 488 if [ "$TEST_TRANSPORT" == "tcp" ] || [ "$TEST_TRANSPORT" == "rdma" ]; then 489 # currently we run the host/perf test for TCP even on systems without kernel nvme-tcp 490 # support; that's fine since the host/perf test uses the SPDK initiator 491 # maybe later we will enforce modprobe to succeed once we have systems in the test pool 492 # with nvme-tcp kernel support - but until then let this pass so we can still run the 493 # host/perf test with the tcp transport 494 modprobe nvme-$TEST_TRANSPORT || true 495 fi 496} 497 498function nvmfappstart() { 499 timing_enter start_nvmf_tgt 500 "${NVMF_APP[@]}" "$@" & 501 nvmfpid=$! 502 waitforlisten $nvmfpid 503 timing_exit start_nvmf_tgt 504 trap 'process_shm --id $NVMF_APP_SHM_ID || :; nvmftestfini' SIGINT SIGTERM EXIT 505} 506 507function nvmftestfini() { 508 nvmfcleanup || : 509 if [ -n "$nvmfpid" ]; then 510 killprocess $nvmfpid 511 fi 512 if [ "$TEST_MODE" == "iso" ]; then 513 $rootdir/scripts/setup.sh reset 514 fi 515 if [[ "$TEST_TRANSPORT" == "tcp" ]]; then 516 nvmf_tcp_fini 517 fi 518} 519 520function rdma_device_init() { 521 load_ib_rdma_modules 522 allocate_nic_ips 523} 524 525function nvme_connect() { 526 local init_count 527 init_count=$(nvme list | wc -l) 528 529 if ! nvme connect "$@"; then return $?; fi 530 531 for i in $(seq 1 10); do 532 if [ $(nvme list | wc -l) -gt $init_count ]; then 533 return 0 534 else 535 sleep 1s 536 fi 537 done 538 return 1 539} 540 541function get_nvme_devs() { 542 local dev _ 543 544 while read -r dev _; do 545 if [[ $dev == /dev/nvme* ]]; then 546 echo "$dev" 547 fi 548 done < <(nvme list) 549} 550 551function gen_nvmf_target_json() { 552 local subsystem config=() 553 554 for subsystem in "${@:-1}"; do 555 config+=( 556 "$( 557 cat <<- EOF 558 { 559 "params": { 560 "name": "Nvme$subsystem", 561 "trtype": "$TEST_TRANSPORT", 562 "traddr": "$NVMF_FIRST_TARGET_IP", 563 "adrfam": "ipv4", 564 "trsvcid": "$NVMF_PORT", 565 "subnqn": "nqn.2016-06.io.spdk:cnode$subsystem", 566 "hostnqn": "nqn.2016-06.io.spdk:host$subsystem", 567 "hdgst": ${hdgst:-false}, 568 "ddgst": ${ddgst:-false} 569 }, 570 "method": "bdev_nvme_attach_controller" 571 } 572 EOF 573 )" 574 ) 575 done 576 jq . <<- JSON 577 { 578 "subsystems": [ 579 { 580 "subsystem": "bdev", 581 "config": [ 582 { 583 "method": "bdev_nvme_set_options", 584 "params": { 585 "action_on_timeout": "none", 586 "timeout_us": 0, 587 "transport_retry_count": 4, 588 "arbitration_burst": 0, 589 "low_priority_weight": 0, 590 "medium_priority_weight": 0, 591 "high_priority_weight": 0, 592 "nvme_adminq_poll_period_us": 10000, 593 "keep_alive_timeout_ms" : 10000, 594 "nvme_ioq_poll_period_us": 0, 595 "io_queue_requests": 0, 596 "delay_cmd_submit": true 597 } 598 }, 599 $( 600 IFS="," 601 printf '%s\n' "${config[*]}" 602 ), 603 { 604 "method": "bdev_wait_for_examine" 605 } 606 ] 607 } 608 ] 609 } 610 JSON 611} 612 613function _remove_spdk_ns() { 614 local ns {ns,mn,an}_net_devs 615 while read -r ns _; do 616 [[ $ns == *_spdk ]] || continue 617 # Gather all devs from the target $ns namespace. We want to differentiate 618 # between veth and physical links and gather just the latter. To do so, 619 # we simply compare ifindex to iflink - as per kernel docs, these should 620 # be always equal for the physical links. For veth devices, since they are 621 # paired, iflink should point at an actual bridge, hence being different 622 # from its own ifindex. 623 ns_net_devs=($( 624 ip netns exec "$ns" bash <<- 'IN_NS' 625 shopt -s extglob nullglob 626 for dev in /sys/class/net/!(lo|bond*); do 627 (($(< "$dev/ifindex") == $(< "$dev/iflink"))) || continue 628 echo "${dev##*/}" 629 done 630 IN_NS 631 )) 632 # Gather all the net devs from the main ns 633 mn_net_devs=($(basename -a /sys/class/net/!(lo|bond*))) 634 # Merge these two to have a list for comparison 635 an_net_devs=($(printf '%s\n' "${ns_net_devs[@]}" "${mn_net_devs[@]}" | sort)) 636 637 ip netns delete "$ns" 638 639 # Check if our list matches against the main ns after $ns got deleted 640 while [[ ${an_net_devs[*]} != "${mn_net_devs[*]}" ]]; do 641 mn_net_devs=($(basename -a /sys/class/net/!(lo|bond*))) 642 sleep 1s 643 done 644 done < <(ip netns list) 645} 646 647remove_spdk_ns() { 648 xtrace_disable_per_cmd _remove_spdk_ns 649} 650 651configure_kernel_target() { 652 local kernel_name=$1 kernel_target_ip=$2 653 # Keep it global in scope for easier cleanup 654 nvmet=/sys/kernel/config/nvmet 655 kernel_subsystem=$nvmet/subsystems/$kernel_name 656 kernel_namespace=$kernel_subsystem/namespaces/1 657 kernel_port=$nvmet/ports/1 658 659 local block nvme 660 661 if [[ ! -e /sys/module/nvmet ]]; then 662 modprobe nvmet 663 fi 664 665 [[ -e $nvmet ]] 666 667 "$rootdir/scripts/setup.sh" reset 668 669 # Find nvme with an active ns device 670 for block in /sys/block/nvme*; do 671 [[ -e $block ]] || continue 672 is_block_zoned "${block##*/}" && continue 673 block_in_use "${block##*/}" || nvme="/dev/${block##*/}" 674 done 675 676 [[ -b $nvme ]] 677 678 mkdir "$kernel_subsystem" 679 mkdir "$kernel_namespace" 680 mkdir "$kernel_port" 681 682 # It allows only %llx value and for some reason kernel swaps the byte order 683 # so setting the serial is not very useful here 684 # "$kernel_subsystem/attr_serial" 685 echo "SPDK-$kernel_name" > "$kernel_subsystem/attr_model" 686 687 echo 1 > "$kernel_subsystem/attr_allow_any_host" 688 echo "$nvme" > "$kernel_namespace/device_path" 689 echo 1 > "$kernel_namespace/enable" 690 691 echo "$kernel_target_ip" > "$kernel_port/addr_traddr" 692 echo "$TEST_TRANSPORT" > "$kernel_port/addr_trtype" 693 echo "$NVMF_PORT" > "$kernel_port/addr_trsvcid" 694 echo ipv4 > "$kernel_port/addr_adrfam" 695 696 # Enable the listener by linking the port to previously created subsystem 697 ln -s "$kernel_subsystem" "$kernel_port/subsystems/" 698 699 # Check if target is available 700 nvme discover "${NVME_HOST[@]}" -a "$kernel_target_ip" -t "$TEST_TRANSPORT" -s "$NVMF_PORT" 701} 702 703clean_kernel_target() { 704 [[ -e $kernel_subsystem ]] || return 0 705 706 echo 0 > "$kernel_namespace/enable" 707 708 rm -f "$kernel_port/subsystems/${kernel_subsystem##*/}" 709 rmdir "$kernel_namespace" 710 rmdir "$kernel_port" 711 rmdir "$kernel_subsystem" 712 713 modules=(/sys/module/nvmet/holders/*) 714 715 modprobe -r "${modules[@]##*/}" nvmet 716 717 # Get back all nvmes to userspace 718 "$rootdir/scripts/setup.sh" 719} 720 721format_key() { 722 local prefix key digest 723 724 prefix="$1" key="$2" digest="$3" 725 python - <<- EOF 726 import base64, zlib 727 728 crc = zlib.crc32(b"$key").to_bytes(4, byteorder="little") 729 b64 = base64.b64encode(b"$key" + crc).decode("utf-8") 730 print("$prefix:{:02x}:{}:".format($digest, b64), end="") 731 EOF 732} 733 734format_interchange_psk() { 735 format_key "NVMeTLSkey-1" "$1" "$2" 736} 737 738format_dhchap_key() { 739 format_key "DHHC-1" "$1" "$2" 740} 741 742gen_dhchap_key() { 743 local digest len file key 744 local -A digests=([null]=0 [sha256]=1 [sha384]=2 [sha512]=3) 745 746 digest="$1" len=$2 747 key=$(xxd -p -c0 -l $((len / 2)) /dev/urandom) 748 file=$(mktemp -t "spdk.key-$1.XXX") 749 format_dhchap_key "$key" "${digests[$1]}" > "$file" 750 chmod 0600 "$file" 751 752 echo "$file" 753} 754 755get_main_ns_ip() { 756 # Determine which ip to use based on nvmftestinit() setup. For tcp we pick 757 # interface which resides in the main net namespace and which is visible 758 # to nvmet under tcp setup. $NVMF_FIRST_TARGET_IP is solely for rdma use. 759 # FIXME: This requires proper unification of the networking setup across 760 # different transports. 761 local ip 762 local -A ip_candidates=() 763 764 ip_candidates["rdma"]=NVMF_FIRST_TARGET_IP 765 ip_candidates["tcp"]=NVMF_INITIATOR_IP 766 767 [[ -z $TEST_TRANSPORT || -z ${ip_candidates["$TEST_TRANSPORT"]} ]] && return 1 768 ip=${ip_candidates["$TEST_TRANSPORT"]} 769 770 if [[ -z ${!ip} ]]; then 771 echo "$ip not set, call nvmftestinit() first" >&2 772 return 1 773 fi 774 775 echo "${!ip}" 776} 777 778uuid2nguid() { 779 tr -d - <<< "${1^^}" 780} 781 782ipts() { iptables "$@" -m comment --comment "SPDK_NVMF:$*"; } 783iptr() { iptables-save | grep -v SPDK_NVMF | iptables-restore; } 784