xref: /spdk/test/nvmf/host/multipath.sh (revision f6866117acb32c78d5ea7bd76ba330284655af35)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2020 Intel Corporation
4#  All rights reserved.
5#
6testdir=$(readlink -f "$(dirname $0)")
7rootdir=$(readlink -f "$testdir/../../..")
8source "$rootdir/test/common/autotest_common.sh"
9source "$rootdir/test/nvmf/common.sh"
10
11MALLOC_BDEV_SIZE=64
12MALLOC_BLOCK_SIZE=512
13
14rpc_py="$rootdir/scripts/rpc.py"
15bpf_sh="$rootdir/scripts/bpftrace.sh"
16
17bdevperf_rpc_sock=/var/tmp/bdevperf.sock
18
19# NQN prefix to use for subsystem NQNs
20NQN=nqn.2016-06.io.spdk:cnode1
21
22cleanup() {
23	process_shm --id $NVMF_APP_SHM_ID || true
24	cat "$testdir/try.txt"
25	rm -f "$testdir/try.txt"
26	killprocess $bdevperf_pid
27	nvmftestfini
28}
29
30nvmftestinit
31
32nvmfappstart -m 0x3
33nvmfapp_pid=$!
34
35$rpc_py nvmf_create_transport $NVMF_TRANSPORT_OPTS -u 8192
36$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE -b Malloc0
37# Set -r to enable ANA reporting feature
38$rpc_py nvmf_create_subsystem $NQN -a -s SPDK00000000000001 -r -m 2
39$rpc_py nvmf_subsystem_add_ns $NQN Malloc0
40$rpc_py nvmf_subsystem_add_listener $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT
41$rpc_py nvmf_subsystem_add_listener $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT
42
43"$rootdir/build/examples/bdevperf" -m 0x4 -z -r $bdevperf_rpc_sock -q 128 -o 4096 -w verify -t 90 &> "$testdir/try.txt" &
44bdevperf_pid=$!
45
46trap 'cleanup; exit 1' SIGINT SIGTERM EXIT
47waitforlisten $bdevperf_pid $bdevperf_rpc_sock
48
49# Create a controller and set multipath behavior
50# bdev_retry_count is set to -1 means infinite reconnects
51$rpc_py -s $bdevperf_rpc_sock bdev_nvme_set_options -r -1
52# -l -1 ctrlr_loss_timeout_sec -1 means infinite reconnects
53# -o 10 reconnect_delay_sec time to delay a reconnect retry is limited to 10 sec
54$rpc_py -s $bdevperf_rpc_sock bdev_nvme_attach_controller -b Nvme0 -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT -f ipv4 -n $NQN -l -1 -o 10
55$rpc_py -s $bdevperf_rpc_sock bdev_nvme_attach_controller -b Nvme0 -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT -f ipv4 -n $NQN -x multipath -l -1 -o 10
56
57function set_ANA_state() {
58	$rpc_py nvmf_subsystem_listener_set_ana_state $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT -n $1
59	$rpc_py nvmf_subsystem_listener_set_ana_state $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT -n $2
60}
61
62# check for io on the expected ANA state port
63function confirm_io_on_port() {
64	$bpf_sh $nvmfapp_pid "$rootdir/scripts/bpf/nvmf_path.bt" &> "$testdir/trace.txt" &
65	dtrace_pid=$!
66	sleep 6
67	active_port=$($rpc_py nvmf_subsystem_get_listeners $NQN | jq -r '.[] | select (.ana_states[0].ana_state=="'$1'") | .address.trsvcid')
68	cat "$testdir/trace.txt"
69	port=$(cut < "$testdir/trace.txt" -d ']' -f1 | awk '$1=="@path['$NVMF_FIRST_TARGET_IP'," {print $2}' | sed -n '1p')
70	[[ "$active_port" == "$port" ]]
71	[[ "$port" == "$2" ]]
72	kill $dtrace_pid
73	rm -f "$testdir/trace.txt"
74}
75
76"$rootdir/examples/bdev/bdevperf/bdevperf.py" -t 120 -s $bdevperf_rpc_sock perform_tests &
77
78sleep 1
79
80# Set ANA state to each listener
81set_ANA_state non_optimized optimized
82# Check the IO on expected port with ANA state set
83confirm_io_on_port "optimized" $NVMF_SECOND_PORT
84
85# Check traffic paths with different ANA states
86set_ANA_state non_optimized inaccessible
87confirm_io_on_port "non_optimized" $NVMF_PORT
88
89set_ANA_state inaccessible optimized
90confirm_io_on_port "optimized" $NVMF_SECOND_PORT
91
92# Not expecting the io on any port
93set_ANA_state inaccessible inaccessible
94confirm_io_on_port "" ""
95
96set_ANA_state non_optimized optimized
97confirm_io_on_port "optimized" $NVMF_SECOND_PORT
98
99# Remove listener to monitor multipath function
100$rpc_py nvmf_subsystem_remove_listener $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT
101sleep 1
102
103# Expect IO on alternate path
104confirm_io_on_port "non_optimized" $NVMF_PORT
105
106# Add listener back with optimized state, traffic should switch to optimized port
107$rpc_py nvmf_subsystem_add_listener $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT
108$rpc_py nvmf_subsystem_listener_set_ana_state $NQN -t $TEST_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s $NVMF_SECOND_PORT -n optimized
109
110# wait for the io to switch to second port
111sleep 6
112confirm_io_on_port "optimized" $NVMF_SECOND_PORT
113
114killprocess $bdevperf_pid
115# Make sure we catch bdevperf's exit status
116wait $bdevperf_pid
117
118cat "$testdir/try.txt"
119
120$rpc_py nvmf_delete_subsystem $NQN
121
122trap - SIGINT SIGTERM EXIT
123
124rm -f "$testdir/try.txt"
125nvmftestfini
126