xref: /spdk/test/nvmf/common.sh (revision e1d06d9954b871531c9b376069d620d2c6cee854)
1NVMF_PORT=4420
2NVMF_SECOND_PORT=4421
3NVMF_THIRD_PORT=4422
4NVMF_IP_PREFIX="192.168.100"
5NVMF_IP_LEAST_ADDR=8
6NVMF_TCP_IP_ADDRESS="127.0.0.1"
7NVMF_TRANSPORT_OPTS=""
8NVMF_SERIAL=SPDK00000000000001
9
10function build_nvmf_app_args() {
11	if [ $SPDK_RUN_NON_ROOT -eq 1 ]; then
12		# We assume that test script is started from sudo
13		NVMF_APP=(sudo -E -u $SUDO_USER "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" "${NVMF_APP[@]}")
14	fi
15	NVMF_APP+=(-i "$NVMF_APP_SHM_ID" -e 0xFFFF)
16
17	if [ -n "$SPDK_HUGE_DIR" ]; then
18		NVMF_APP+=(--huge-dir "$SPDK_HUGE_DIR")
19	elif [ $SPDK_RUN_NON_ROOT -eq 1 ]; then
20		echo "In non-root test mode you have to set SPDK_HUGE_DIR variable." >&2
21		echo "For example:" >&2
22		echo "sudo mkdir /mnt/spdk_hugetlbfs" >&2
23		echo "sudo chown ${SUDO_USER}: /mnt/spdk_hugetlbfs" >&2
24		echo "export SPDK_HUGE_DIR=/mnt/spdk_hugetlbfs" >&2
25		return 1
26	fi
27}
28
29: ${NVMF_APP_SHM_ID="0"}
30export NVMF_APP_SHM_ID
31build_nvmf_app_args
32
33have_pci_nics=0
34
35function rxe_cfg() {
36	"$rootdir/scripts/rxe_cfg_small.sh" "$@"
37}
38
39function load_ib_rdma_modules() {
40	if [ $(uname) != Linux ]; then
41		return 0
42	fi
43
44	modprobe ib_cm
45	modprobe ib_core
46	# Newer kernels do not have the ib_ucm module
47	modprobe ib_ucm || true
48	modprobe ib_umad
49	modprobe ib_uverbs
50	modprobe iw_cm
51	modprobe rdma_cm
52	modprobe rdma_ucm
53}
54
55function detect_soft_roce_nics() {
56	rxe_cfg stop # make sure we run tests with a clean slate
57	rxe_cfg start
58}
59
60# args 1 and 2 represent the grep filters for finding our NICS.
61# subsequent args are all drivers that should be loaded if we find these NICs.
62# Those drivers should be supplied in the correct order.
63function detect_nics_and_probe_drivers() {
64	NIC_VENDOR="$1"
65	NIC_CLASS="$2"
66
67	nvmf_nic_bdfs=$(lspci | grep Ethernet | grep "$NIC_VENDOR" | grep "$NIC_CLASS" | awk -F ' ' '{print "0000:"$1}')
68
69	if [ -z "$nvmf_nic_bdfs" ]; then
70		return 0
71	fi
72
73	have_pci_nics=1
74	if [ $# -ge 2 ]; then
75		# shift out the first two positional arguments.
76		shift 2
77		# Iterate through the remaining arguments.
78		for i; do
79			if [[ $i == irdma ]]; then
80				# Our tests don't play well with iWARP protocol. Make sure we use RoCEv2 instead.
81				if [[ -e /sys/module/irdma/parameters/roce_ena ]]; then
82					# reload the module to re-init the rdma devices
83					(($(< /sys/module/irdma/parameters/roce_ena) != 1)) && modprobe -r irdma
84				fi
85				modprobe "$i" roce_ena=1
86			else
87				modprobe "$i"
88			fi
89		done
90	fi
91}
92
93function pci_rdma_switch() {
94	local driver=$1
95
96	local -a driver_args=()
97	driver_args+=("Mellanox ConnectX-4 mlx5_core mlx5_ib")
98	driver_args+=("Mellanox ConnectX-5 mlx5_core mlx5_ib")
99	driver_args+=("Intel E810 ice irdma")
100	driver_args+=("Intel X722 i40e i40iw")
101	driver_args+=("Chelsio \"Unified Wire\" cxgb4 iw_cxgb4")
102
103	case $driver in
104		mlx5_ib)
105			detect_nics_and_probe_drivers ${driver_args[0]}
106			detect_nics_and_probe_drivers ${driver_args[1]}
107			;;
108		irdma)
109			detect_nics_and_probe_drivers ${driver_args[2]}
110			;;
111		i40iw)
112			detect_nics_and_probe_drivers ${driver_args[3]}
113			;;
114		iw_cxgb4)
115			detect_nics_and_probe_drivers ${driver_args[4]}
116			;;
117		*)
118			for d in "${driver_args[@]}"; do
119				detect_nics_and_probe_drivers $d
120			done
121			;;
122	esac
123}
124
125function pci_tcp_switch() {
126	local driver=$1
127
128	local -a driver_args=()
129	driver_args+=("Intel E810 ice")
130
131	case $driver in
132		ice)
133			detect_nics_and_probe_drivers ${driver_args[0]}
134			;;
135		*)
136			for d in "${driver_args[@]}"; do
137				detect_nics_and_probe_drivers $d
138			done
139			;;
140	esac
141}
142
143function detect_pci_nics() {
144
145	if ! hash lspci; then
146		return 0
147	fi
148
149	local nic_drivers
150	local found_drivers
151
152	if [[ -z "$TEST_TRANSPORT" ]]; then
153		TEST_TRANSPORT=$SPDK_TEST_NVMF_TRANSPORT
154	fi
155
156	if [[ "$TEST_TRANSPORT" == "rdma" ]]; then
157		nic_drivers="mlx5_ib|irdma|i40iw|iw_cxgb4"
158
159		# Try to find RDMA drivers which are already loded and try to
160		# use only it's associated NICs, without probing all drivers.
161		found_drivers=$(lsmod | grep -Eo $nic_drivers | sort -u)
162		for d in $found_drivers; do
163			pci_rdma_switch $d
164		done
165
166		# In case lsmod reported driver, but lspci does not report
167		# physical NICs - fall back to old approach any try to
168		# probe all compatible NICs.
169		((have_pci_nics == 0)) && pci_rdma_switch "default"
170
171	elif [[ "$TEST_TRANSPORT" == "tcp" ]]; then
172		nic_drivers="ice"
173		found_drivers=$(lsmod | grep -Eo $nic_drivers | sort -u)
174		for d in $found_drivers; do
175			pci_tcp_switch $d
176		done
177		((have_pci_nics == 0)) && pci_tcp_switch "default"
178	fi
179
180	# Use softroce if everything else failed.
181	((have_pci_nics == 0)) && return 0
182
183	# Provide time for drivers to properly load.
184	sleep 5
185}
186
187function detect_transport_nics() {
188	detect_pci_nics
189	if [ "$have_pci_nics" -eq "0" ]; then
190		detect_soft_roce_nics
191	fi
192}
193
194function allocate_nic_ips() {
195	((count = NVMF_IP_LEAST_ADDR))
196	for nic_name in $(get_rdma_if_list); do
197		ip="$(get_ip_address $nic_name)"
198		if [[ -z $ip ]]; then
199			ip addr add $NVMF_IP_PREFIX.$count/24 dev $nic_name
200			ip link set $nic_name up
201			((count = count + 1))
202		fi
203		# dump configuration for debug log
204		ip addr show $nic_name
205	done
206}
207
208function get_available_rdma_ips() {
209	for nic_name in $(get_rdma_if_list); do
210		get_ip_address $nic_name
211	done
212}
213
214function get_rdma_if_list() {
215	rxe_cfg rxe-net
216}
217
218function get_tcp_if_list_by_driver() {
219	local driver
220	driver=${1:-ice}
221
222	shopt -s nullglob
223	tcp_if_list=(/sys/bus/pci/drivers/$driver/0000*/net/*)
224	shopt -u nullglob
225	printf '%s\n' "${tcp_if_list[@]##*/}"
226}
227
228function get_ip_address() {
229	interface=$1
230	ip -o -4 addr show $interface | awk '{print $4}' | cut -d"/" -f1
231}
232
233function nvmfcleanup() {
234	sync
235
236	if [ "$TEST_TRANSPORT" == "tcp" ] || [ "$TEST_TRANSPORT" == "rdma" ]; then
237		set +e
238		for i in {1..20}; do
239			modprobe -v -r nvme-$TEST_TRANSPORT
240			if modprobe -v -r nvme-fabrics; then
241				set -e
242				return 0
243			fi
244			sleep 1
245		done
246		set -e
247
248		# So far unable to remove the kernel modules. Try
249		# one more time and let it fail.
250		# Allow the transport module to fail for now. See Jim's comment
251		# about the nvme-tcp module below.
252		modprobe -v -r nvme-$TEST_TRANSPORT || true
253		modprobe -v -r nvme-fabrics
254	fi
255}
256
257function nvmf_veth_init() {
258	NVMF_INITIATOR_IP=10.0.0.1
259	NVMF_FIRST_TARGET_IP=10.0.0.2
260	NVMF_SECOND_TARGET_IP=10.0.0.3
261	NVMF_BRIDGE="nvmf_br"
262	NVMF_INITIATOR_INTERFACE="nvmf_init_if"
263	NVMF_INITIATOR_BRIDGE="nvmf_init_br"
264	NVMF_TARGET_NAMESPACE="nvmf_tgt_ns"
265	NVMF_TARGET_NS_CMD=(ip netns exec "$NVMF_TARGET_NAMESPACE")
266	NVMF_TARGET_INTERFACE="nvmf_tgt_if"
267	NVMF_TARGET_INTERFACE2="nvmf_tgt_if2"
268	NVMF_TARGET_BRIDGE="nvmf_tgt_br"
269	NVMF_TARGET_BRIDGE2="nvmf_tgt_br2"
270
271	ip link set $NVMF_INITIATOR_BRIDGE nomaster || true
272	ip link set $NVMF_TARGET_BRIDGE nomaster || true
273	ip link set $NVMF_TARGET_BRIDGE2 nomaster || true
274	ip link set $NVMF_INITIATOR_BRIDGE down || true
275	ip link set $NVMF_TARGET_BRIDGE down || true
276	ip link set $NVMF_TARGET_BRIDGE2 down || true
277	ip link delete $NVMF_BRIDGE type bridge || true
278	ip link delete $NVMF_INITIATOR_INTERFACE || true
279	"${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE || true
280	"${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE2 || true
281	ip netns del $NVMF_TARGET_NAMESPACE || true
282
283	# Create network namespace
284	ip netns add $NVMF_TARGET_NAMESPACE
285
286	# Create veth (Virtual ethernet) interface pairs
287	ip link add $NVMF_INITIATOR_INTERFACE type veth peer name $NVMF_INITIATOR_BRIDGE
288	ip link add $NVMF_TARGET_INTERFACE type veth peer name $NVMF_TARGET_BRIDGE
289	ip link add $NVMF_TARGET_INTERFACE2 type veth peer name $NVMF_TARGET_BRIDGE2
290
291	# Associate veth interface pairs with network namespace
292	ip link set $NVMF_TARGET_INTERFACE netns $NVMF_TARGET_NAMESPACE
293	ip link set $NVMF_TARGET_INTERFACE2 netns $NVMF_TARGET_NAMESPACE
294
295	# Allocate IP addresses
296	ip addr add $NVMF_INITIATOR_IP/24 dev $NVMF_INITIATOR_INTERFACE
297	"${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_FIRST_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE
298	"${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_SECOND_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE2
299
300	# Link up veth interfaces
301	ip link set $NVMF_INITIATOR_INTERFACE up
302	ip link set $NVMF_INITIATOR_BRIDGE up
303	ip link set $NVMF_TARGET_BRIDGE up
304	ip link set $NVMF_TARGET_BRIDGE2 up
305	"${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE up
306	"${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE2 up
307	"${NVMF_TARGET_NS_CMD[@]}" ip link set lo up
308
309	# Create a bridge
310	ip link add $NVMF_BRIDGE type bridge
311	ip link set $NVMF_BRIDGE up
312
313	# Add veth interfaces to the bridge
314	ip link set $NVMF_INITIATOR_BRIDGE master $NVMF_BRIDGE
315	ip link set $NVMF_TARGET_BRIDGE master $NVMF_BRIDGE
316	ip link set $NVMF_TARGET_BRIDGE2 master $NVMF_BRIDGE
317
318	# Accept connections from veth interface
319	iptables -I INPUT 1 -i $NVMF_INITIATOR_INTERFACE -p tcp --dport $NVMF_PORT -j ACCEPT
320
321	# Verify connectivity
322	ping -c 1 $NVMF_FIRST_TARGET_IP
323	ping -c 1 $NVMF_SECOND_TARGET_IP
324	"${NVMF_TARGET_NS_CMD[@]}" ping -c 1 $NVMF_INITIATOR_IP
325
326	NVMF_APP=("${NVMF_TARGET_NS_CMD[@]}" "${NVMF_APP[@]}")
327}
328
329function nvmf_veth_fini() {
330	# Cleanup bridge, veth interfaces, and network namespace
331	# Note: removing one veth removes the pair
332	ip link set $NVMF_INITIATOR_BRIDGE nomaster
333	ip link set $NVMF_TARGET_BRIDGE nomaster
334	ip link set $NVMF_TARGET_BRIDGE2 nomaster
335	ip link set $NVMF_INITIATOR_BRIDGE down
336	ip link set $NVMF_TARGET_BRIDGE down
337	ip link set $NVMF_TARGET_BRIDGE2 down
338	ip link delete $NVMF_BRIDGE type bridge
339	ip link delete $NVMF_INITIATOR_INTERFACE
340	"${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE
341	"${NVMF_TARGET_NS_CMD[@]}" ip link delete $NVMF_TARGET_INTERFACE2
342	ip netns del $NVMF_TARGET_NAMESPACE
343}
344
345function nvmf_tcp_init() {
346	NVMF_INITIATOR_IP=10.0.0.1
347	NVMF_FIRST_TARGET_IP=10.0.0.2
348	TCP_INTERFACE_LIST=($(get_tcp_if_list_by_driver))
349	if ((${#TCP_INTERFACE_LIST[@]} == 0)); then
350		nvmf_veth_init
351		return 0
352	fi
353
354	# We need two net devs at minimum
355	((${#TCP_INTERFACE_LIST[@]} > 1))
356
357	NVMF_TARGET_INTERFACE=${TCP_INTERFACE_LIST[0]}
358	NVMF_INITIATOR_INTERFACE=${TCP_INTERFACE_LIST[1]}
359
360	# Skip case nvmf_multipath in nvmf_tcp_init(), it will be covered by nvmf_veth_init().
361	NVMF_SECOND_TARGET_IP=""
362
363	NVMF_TARGET_NAMESPACE=$NVMF_TARGET_INTERFACE"_ns"
364	NVMF_TARGET_NS_CMD=(ip netns exec "$NVMF_TARGET_NAMESPACE")
365	ip netns del $NVMF_TARGET_NAMESPACE || true
366	ip -4 addr flush $NVMF_TARGET_INTERFACE || true
367	ip -4 addr flush $NVMF_INITIATOR_INTERFACE || true
368
369	# Create network namespace
370	ip netns add $NVMF_TARGET_NAMESPACE
371
372	# Associate phy interface pairs with network namespace
373	ip link set $NVMF_TARGET_INTERFACE netns $NVMF_TARGET_NAMESPACE
374
375	# Allocate IP addresses
376	ip addr add $NVMF_INITIATOR_IP/24 dev $NVMF_INITIATOR_INTERFACE
377	"${NVMF_TARGET_NS_CMD[@]}" ip addr add $NVMF_FIRST_TARGET_IP/24 dev $NVMF_TARGET_INTERFACE
378
379	# Link up phy interfaces
380	ip link set $NVMF_INITIATOR_INTERFACE up
381
382	"${NVMF_TARGET_NS_CMD[@]}" ip link set $NVMF_TARGET_INTERFACE up
383	"${NVMF_TARGET_NS_CMD[@]}" ip link set lo up
384
385	# Accept connections from phy interface
386	iptables -I INPUT 1 -i $NVMF_INITIATOR_INTERFACE -p tcp --dport $NVMF_PORT -j ACCEPT
387
388	# Verify connectivity
389	ping -c 1 $NVMF_FIRST_TARGET_IP
390	"${NVMF_TARGET_NS_CMD[@]}" ping -c 1 $NVMF_INITIATOR_IP
391
392	NVMF_APP=("${NVMF_TARGET_NS_CMD[@]}" "${NVMF_APP[@]}")
393}
394
395function nvmf_tcp_fini() {
396	if [[ "$NVMF_TARGET_NAMESPACE" == "nvmf_tgt_ns" ]]; then
397		nvmf_veth_fini
398		return 0
399	fi
400	if [[ -n $NVMF_TARGET_NAMESPACE && -e /var/run/netns/$NVMF_TARGET_NAMESPACE ]]; then
401		ip netns del $NVMF_TARGET_NAMESPACE
402	fi
403	ip -4 addr flush $NVMF_INITIATOR_INTERFACE || :
404}
405
406function nvmftestinit() {
407	if [ -z $TEST_TRANSPORT ]; then
408		echo "transport not specified - use --transport= to specify"
409		return 1
410	fi
411
412	trap 'process_shm --id $NVMF_APP_SHM_ID || :; nvmftestfini' SIGINT SIGTERM EXIT
413
414	if [ "$TEST_MODE" == "iso" ]; then
415		$rootdir/scripts/setup.sh
416		if [[ "$TEST_TRANSPORT" == "rdma" ]]; then
417			rdma_device_init
418		fi
419		if [[ "$TEST_TRANSPORT" == "tcp" ]]; then
420			tcp_device_init
421		fi
422	fi
423
424	NVMF_TRANSPORT_OPTS="-t $TEST_TRANSPORT"
425	if [[ "$TEST_TRANSPORT" == "rdma" ]]; then
426		RDMA_IP_LIST=$(get_available_rdma_ips)
427		NVMF_FIRST_TARGET_IP=$(echo "$RDMA_IP_LIST" | head -n 1)
428		NVMF_SECOND_TARGET_IP=$(echo "$RDMA_IP_LIST" | tail -n +2 | head -n 1)
429		if [ -z $NVMF_FIRST_TARGET_IP ]; then
430			echo "no RDMA NIC for nvmf test"
431			exit 0
432		fi
433	elif [[ "$TEST_TRANSPORT" == "tcp" ]]; then
434		nvmf_tcp_init
435		NVMF_TRANSPORT_OPTS="$NVMF_TRANSPORT_OPTS -o"
436	fi
437
438	if [ "$TEST_TRANSPORT" == "tcp" ] || [ "$TEST_TRANSPORT" == "rdma" ]; then
439		# currently we run the host/perf test for TCP even on systems without kernel nvme-tcp
440		#  support; that's fine since the host/perf test uses the SPDK initiator
441		# maybe later we will enforce modprobe to succeed once we have systems in the test pool
442		#  with nvme-tcp kernel support - but until then let this pass so we can still run the
443		#  host/perf test with the tcp transport
444		modprobe nvme-$TEST_TRANSPORT || true
445	fi
446}
447
448function nvmfappstart() {
449	timing_enter start_nvmf_tgt
450	"${NVMF_APP[@]}" "$@" &
451	nvmfpid=$!
452	waitforlisten $nvmfpid
453	timing_exit start_nvmf_tgt
454}
455
456function nvmftestfini() {
457	nvmfcleanup || :
458	if [ -n "$nvmfpid" ]; then
459		killprocess $nvmfpid
460	fi
461	if [ "$TEST_MODE" == "iso" ]; then
462		$rootdir/scripts/setup.sh reset
463		if [[ "$TEST_TRANSPORT" == "rdma" ]]; then
464			rdma_device_init
465		fi
466	fi
467	if [[ "$TEST_TRANSPORT" == "tcp" ]]; then
468		nvmf_tcp_fini
469	fi
470}
471
472function rdma_device_init() {
473	load_ib_rdma_modules
474	detect_transport_nics
475	allocate_nic_ips
476}
477
478function tcp_device_init() {
479	detect_transport_nics
480}
481
482function revert_soft_roce() {
483	rxe_cfg stop
484}
485
486function check_ip_is_soft_roce() {
487	if [ "$TEST_TRANSPORT" != "rdma" ]; then
488		return 0
489	fi
490	rxe_cfg status rxe | grep -wq "$1"
491}
492
493function nvme_connect() {
494	local init_count
495	init_count=$(nvme list | wc -l)
496
497	if ! nvme connect "$@"; then return $?; fi
498
499	for i in $(seq 1 10); do
500		if [ $(nvme list | wc -l) -gt $init_count ]; then
501			return 0
502		else
503			sleep 1s
504		fi
505	done
506	return 1
507}
508
509function get_nvme_devs() {
510	local dev _
511
512	while read -r dev _; do
513		if [[ $dev == /dev/nvme* ]]; then
514			echo "$dev"
515		fi
516	done < <(nvme list)
517}
518
519function gen_nvmf_target_json() {
520	local subsystem config=()
521
522	for subsystem in "${@:-1}"; do
523		config+=(
524			"$(
525				cat <<- EOF
526					{
527					  "params": {
528					    "name": "Nvme$subsystem",
529					    "trtype": "$TEST_TRANSPORT",
530					    "traddr": "$NVMF_FIRST_TARGET_IP",
531					    "adrfam": "ipv4",
532					    "trsvcid": "$NVMF_PORT",
533					    "subnqn": "nqn.2016-06.io.spdk:cnode$subsystem",
534					    "hostnqn": "nqn.2016-06.io.spdk:host$subsystem",
535					    "hdgst": ${hdgst:-false},
536					    "ddgst": ${ddgst:-false}
537					  },
538					  "method": "bdev_nvme_attach_controller"
539					}
540				EOF
541			)"
542		)
543	done
544	jq . <<- JSON
545		{
546		  "subsystems": [
547		    {
548		      "subsystem": "bdev",
549		      "config": [
550			{
551			  "method": "bdev_nvme_set_options",
552			  "params": {
553				"action_on_timeout": "none",
554				"timeout_us": 0,
555				"retry_count": 4,
556				"arbitration_burst": 0,
557				"low_priority_weight": 0,
558				"medium_priority_weight": 0,
559				"high_priority_weight": 0,
560				"nvme_adminq_poll_period_us": 10000,
561				"keep_alive_timeout_ms" : 10000,
562				"nvme_ioq_poll_period_us": 0,
563				"io_queue_requests": 0,
564				"delay_cmd_submit": true
565			  }
566			},
567		        $(
568		IFS=","
569		printf '%s\n' "${config[*]}"
570		),
571			{
572			  "method": "bdev_wait_for_examine"
573			}
574		      ]
575		    }
576		  ]
577		}
578	JSON
579}
580