xref: /spdk/test/json_config/json_config.sh (revision c9ec1e2b106aebe5cd41868d980921a3fa1a8f15)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2018 Intel Corporation
4#  All rights reserved.
5#
6rootdir=$(readlink -f $(dirname $0)/../..)
7source "$rootdir/test/common/autotest_common.sh"
8source "$rootdir/test/nvmf/common.sh"
9source "$rootdir/test/json_config/common.sh"
10
11if [[ $SPDK_TEST_ISCSI -eq 1 ]]; then
12	source "$rootdir/test/iscsi_tgt/common.sh"
13fi
14
15if [[ $SPDK_TEST_VHOST -ne 1 && $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
16	SPDK_TEST_VHOST=1
17	echo "WARNING: Virtio initiator JSON_config test requires vhost target."
18	echo "         Setting SPDK_TEST_VHOST=1 for duration of current script."
19fi
20
21if ((SPDK_TEST_BLOCKDEV + \
22	SPDK_TEST_ISCSI + \
23	SPDK_TEST_NVMF + \
24	SPDK_TEST_VHOST + \
25	SPDK_TEST_VHOST_INIT + \
26	SPDK_TEST_RBD == 0)); then
27	echo "WARNING: No tests are enabled so not running JSON configuration tests"
28	exit 0
29fi
30
31declare -A app_pid=([target]="" [initiator]="")
32declare -A app_socket=([target]='/var/tmp/spdk_tgt.sock' [initiator]='/var/tmp/spdk_initiator.sock')
33declare -A app_params=([target]='-m 0x1 -s 1024' [initiator]='-m 0x2 -g -u -s 1024')
34declare -A configs_path=([target]="$rootdir/spdk_tgt_config.json" [initiator]="$rootdir/spdk_initiator_config.json")
35
36function initiator_rpc() {
37	$rootdir/scripts/rpc.py -s "${app_socket[initiator]}" "$@"
38}
39
40last_event_id=0
41
42function tgt_check_notification_types() {
43	timing_enter "${FUNCNAME[0]}"
44
45	local ret=0
46	local enabled_types=("bdev_register" "bdev_unregister")
47	if [[ $CONFIG_FSDEV == y ]]; then
48		enabled_types+=("fsdev_register" "fsdev_unregister")
49	fi
50
51	local get_types=($(tgt_rpc notify_get_types | jq -r '.[]'))
52
53	local type_diff
54	type_diff=$(echo "${enabled_types[@]}" "${get_types[@]}" | tr ' ' '\n' | sort | uniq -u)
55
56	if [[ -n "$type_diff" ]]; then
57		echo "ERROR: expected types: ${enabled_types[*]}, but got: ${get_types[*]}"
58		ret=1
59	fi
60
61	timing_exit "${FUNCNAME[0]}"
62	return $ret
63}
64
65get_notifications() {
66	local ev_type ev_ctx event_id
67
68	while IFS=":" read -r ev_type ev_ctx event_id; do
69		echo "$ev_type:$ev_ctx"
70	done < <(tgt_rpc notify_get_notifications -i "$last_event_id" | jq -r '.[] | "\(.type):\(.ctx):\(.id)"')
71}
72
73function tgt_check_notifications() {
74	local events_to_check
75	local recorded_events
76
77	# Seems like notifications don't necessarily have to come in order, so make sure they are sorted
78	events_to_check=($(printf '%s\n' "$@" | sort))
79	recorded_events=($(get_notifications | sort))
80
81	if [[ ${events_to_check[*]} != "${recorded_events[*]}" ]]; then
82		cat <<- ERROR
83			Expected events did not match.
84
85			Expected:
86			$(printf ' %s\n' "${events_to_check[@]}")
87			Recorded:
88			$(printf ' %s\n' "${recorded_events[@]}")
89		ERROR
90		return 1
91	fi
92
93	cat <<- INFO
94		Expected events matched:
95		$(printf ' %s\n' "${recorded_events[@]}")
96	INFO
97}
98
99function create_accel_config() {
100	timing_enter "${FUNCNAME[0]}"
101
102	if [[ $SPDK_TEST_CRYPTO -eq 1 ]]; then
103		tgt_rpc dpdk_cryptodev_scan_accel_module
104		tgt_rpc accel_assign_opc -o encrypt -m dpdk_cryptodev
105		tgt_rpc accel_assign_opc -o decrypt -m dpdk_cryptodev
106	fi
107
108	timing_exit "${FUNCNAME[0]}"
109}
110
111function create_bdev_subsystem_config() {
112	timing_enter "${FUNCNAME[0]}"
113
114	local expected_notifications=()
115
116	# Consider multiple nvme devices loaded into the subsystem prior running
117	# the tests.
118	expected_notifications+=($(get_notifications))
119
120	if [[ $SPDK_TEST_BLOCKDEV -eq 1 ]]; then
121		local lvol_store_base_bdev=Nvme0n1
122
123		tgt_rpc bdev_split_create $lvol_store_base_bdev 2
124		tgt_rpc bdev_split_create Malloc0 3
125		tgt_rpc bdev_malloc_create 8 4096 --name Malloc3
126		tgt_rpc bdev_passthru_create -b Malloc3 -p PTBdevFromMalloc3
127
128		tgt_rpc bdev_null_create Null0 32 512
129
130		tgt_rpc bdev_malloc_create 32 512 --name Malloc0
131		tgt_rpc bdev_malloc_create 16 4096 --name Malloc1
132
133		expected_notifications+=(
134			bdev_register:${lvol_store_base_bdev}p1
135			bdev_register:${lvol_store_base_bdev}p0
136			bdev_register:Malloc3
137			bdev_register:PTBdevFromMalloc3
138			bdev_register:Null0
139			bdev_register:Malloc0
140			bdev_register:Malloc0p2
141			bdev_register:Malloc0p1
142			bdev_register:Malloc0p0
143			bdev_register:Malloc1
144		)
145
146		# This AIO bdev must be large enough to be used as LVOL store
147		dd if=/dev/zero of="$SPDK_TEST_STORAGE/sample_aio" bs=1024 count=102400
148		tgt_rpc bdev_aio_create "$SPDK_TEST_STORAGE/sample_aio" aio_disk 1024
149		expected_notifications+=(bdev_register:aio_disk)
150
151		# For LVOLs use split to check for proper order of initialization.
152		# If LVOLs configuration will be reordered (eg moved before splits or AIO/NVMe)
153		# it should fail loading JSON config from file.
154		tgt_rpc bdev_lvol_create_lvstore -c 1048576 ${lvol_store_base_bdev}p0 lvs_test
155
156		expected_notifications+=(
157			"bdev_register:$(tgt_rpc bdev_lvol_create -l lvs_test lvol0 32)"
158			"bdev_register:$(tgt_rpc bdev_lvol_create -l lvs_test -t lvol1 32)"
159			"bdev_register:$(tgt_rpc bdev_lvol_snapshot lvs_test/lvol0 snapshot0)"
160			"bdev_register:$(tgt_rpc bdev_lvol_clone lvs_test/snapshot0 clone0)"
161		)
162	fi
163
164	if [[ $SPDK_TEST_CRYPTO -eq 1 ]]; then
165		tgt_rpc bdev_malloc_create 8 1024 --name MallocForCryptoBdev
166		if [[ $(lspci -d:37c8 | wc -l) -eq 0 ]]; then
167			local crypto_driver=crypto_aesni_mb
168		else
169			local crypto_driver=crypto_qat
170		fi
171
172		tgt_rpc bdev_crypto_create MallocForCryptoBdev CryptoMallocBdev -p $crypto_driver -k 01234567891234560123456789123456
173		expected_notifications+=(
174			bdev_register:MallocForCryptoBdev
175			bdev_register:CryptoMallocBdev
176		)
177	fi
178
179	if [[ $SPDK_TEST_RBD -eq 1 ]]; then
180		rbd_setup 127.0.0.1
181		tgt_rpc bdev_rbd_create $RBD_POOL $RBD_NAME 4096
182		expected_notifications+=(bdev_register:Ceph0)
183	fi
184
185	tgt_check_notifications "${expected_notifications[@]}"
186
187	timing_exit "${FUNCNAME[0]}"
188}
189
190function cleanup_bdev_subsystem_config() {
191	timing_enter "${FUNCNAME[0]}"
192
193	if [[ $SPDK_TEST_BLOCKDEV -eq 1 ]]; then
194		tgt_rpc bdev_lvol_delete lvs_test/clone0
195		tgt_rpc bdev_lvol_delete lvs_test/lvol0
196		tgt_rpc bdev_lvol_delete lvs_test/snapshot0
197		tgt_rpc bdev_lvol_delete_lvstore -l lvs_test
198	fi
199
200	if [[ $(uname -s) = Linux ]]; then
201		rm -f "$SPDK_TEST_STORAGE/sample_aio"
202	fi
203
204	if [[ $SPDK_TEST_RBD -eq 1 ]]; then
205		rbd_cleanup
206	fi
207
208	timing_exit "${FUNCNAME[0]}"
209}
210
211function create_vhost_subsystem_config() {
212	timing_enter "${FUNCNAME[0]}"
213
214	tgt_rpc bdev_malloc_create 64 1024 --name MallocForVhost0
215	tgt_rpc bdev_split_create MallocForVhost0 8
216
217	tgt_rpc vhost_create_scsi_controller VhostScsiCtrlr0
218	tgt_rpc vhost_scsi_controller_add_target VhostScsiCtrlr0 0 MallocForVhost0p3
219	tgt_rpc vhost_scsi_controller_add_target VhostScsiCtrlr0 -1 MallocForVhost0p4
220	tgt_rpc vhost_controller_set_coalescing VhostScsiCtrlr0 1 100
221
222	tgt_rpc vhost_create_blk_controller VhostBlkCtrlr0 MallocForVhost0p5
223
224	timing_exit "${FUNCNAME[0]}"
225}
226
227function create_iscsi_subsystem_config() {
228	timing_enter "${FUNCNAME[0]}"
229	tgt_rpc bdev_malloc_create 64 1024 --name MallocForIscsi0
230	tgt_rpc iscsi_create_portal_group $PORTAL_TAG 127.0.0.1:$ISCSI_PORT
231	tgt_rpc iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
232	tgt_rpc iscsi_create_target_node Target3 Target3_alias 'MallocForIscsi0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
233	timing_exit "${FUNCNAME[0]}"
234}
235
236function create_nvmf_subsystem_config() {
237	timing_enter "${FUNCNAME[0]}"
238
239	NVMF_FIRST_TARGET_IP="127.0.0.1"
240	if [[ $SPDK_TEST_NVMF_TRANSPORT == "rdma" ]]; then
241		TEST_TRANSPORT=$SPDK_TEST_NVMF_TRANSPORT nvmftestinit
242	fi
243
244	if [[ -z $NVMF_FIRST_TARGET_IP ]]; then
245		echo "Error: no NIC for nvmf test"
246		return 1
247	fi
248
249	tgt_rpc bdev_malloc_create 8 512 --name MallocForNvmf0
250	tgt_rpc bdev_malloc_create 4 1024 --name MallocForNvmf1
251
252	tgt_rpc nvmf_create_transport -t $SPDK_TEST_NVMF_TRANSPORT -u 8192 -c 0
253	tgt_rpc nvmf_create_subsystem nqn.2016-06.io.spdk:cnode1 -a -s SPDK00000000000001
254	tgt_rpc nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 MallocForNvmf0
255	tgt_rpc nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 MallocForNvmf1
256	tgt_rpc nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode1 -t $SPDK_TEST_NVMF_TRANSPORT -a $NVMF_FIRST_TARGET_IP -s "$NVMF_PORT"
257
258	timing_exit "${FUNCNAME[0]}"
259}
260
261function create_virtio_initiator_config() {
262	timing_enter "${FUNCNAME[0]}"
263	initiator_rpc bdev_virtio_attach_controller -t user -a /var/tmp/VhostScsiCtrlr0 -d scsi VirtioScsiCtrlr0
264	initiator_rpc bdev_virtio_attach_controller -t user -a /var/tmp/VhostBlkCtrlr0 -d blk VirtioBlk0
265	timing_exit "${FUNCNAME[0]}"
266}
267
268function json_config_test_init() {
269	timing_enter "${FUNCNAME[0]}"
270	timing_enter json_config_setup_target
271
272	json_config_test_start_app target --wait-for-rpc
273
274	#TODO: global subsystem params
275
276	create_accel_config
277
278	# Load nvme configuration. The load_config will issue framework_start_init automatically
279	(
280		$rootdir/scripts/gen_nvme.sh --json-with-subsystems
281	) | tgt_rpc load_config
282
283	tgt_check_notification_types
284
285	if [[ $SPDK_TEST_BLOCKDEV -eq 1 ]]; then
286		create_bdev_subsystem_config
287	fi
288
289	if [[ $SPDK_TEST_VHOST -eq 1 ]]; then
290		create_vhost_subsystem_config
291	fi
292
293	if [[ $SPDK_TEST_ISCSI -eq 1 ]]; then
294		create_iscsi_subsystem_config
295	fi
296
297	if [[ $SPDK_TEST_NVMF -eq 1 ]]; then
298		create_nvmf_subsystem_config
299	fi
300	timing_exit json_config_setup_target
301
302	if [[ $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
303		json_config_test_start_app initiator
304		create_virtio_initiator_config
305	fi
306
307	tgt_rpc bdev_malloc_create 8 512 --name MallocBdevForConfigChangeCheck
308
309	timing_exit "${FUNCNAME[0]}"
310}
311
312function json_config_test_fini() {
313	timing_enter "${FUNCNAME[0]}"
314	local ret=0
315
316	if [[ -n "${app_pid[initiator]}" ]]; then
317		if [[ $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
318			initiator_rpc bdev_virtio_detach_controller VirtioScsiCtrlr0 || :
319			initiator_rpc bdev_virtio_detach_controller VirtioBlk0 || :
320		fi
321		killprocess ${app_pid[initiator]}
322	fi
323
324	if [[ -n "${app_pid[target]}" ]]; then
325
326		# Remove any artifacts we created (files, lvol etc)
327		cleanup_bdev_subsystem_config
328
329		# SPDK_TEST_NVMF: Should we clear something?
330		killprocess ${app_pid[target]}
331	fi
332
333	rm -f "${configs_path[@]}"
334	timing_exit "${FUNCNAME[0]}"
335	return $ret
336}
337
338function json_config_clear() {
339	[[ -n "${#app_socket[$1]}" ]] # Check app type
340	$rootdir/test/json_config/clear_config.py -s ${app_socket[$1]} clear_config
341
342	# Check if config is clean.
343	# Global params can't be cleared so need to filter them out.
344	local config_filter="$rootdir/test/json_config/config_filter.py"
345
346	# RPC's used to cleanup configuration (e.g. to delete split and nvme bdevs)
347	# complete immediately and they don't wait for the unregister callback.
348	# It causes that configuration may not be fully cleaned at this moment and
349	# we should to wait a while. (See github issue #789)
350	count=100
351	while [ $count -gt 0 ]; do
352		$rootdir/scripts/rpc.py -s "${app_socket[$1]}" save_config | $config_filter -method delete_global_parameters | $config_filter -method check_empty && break
353		count=$((count - 1))
354		sleep 0.1
355	done
356
357	if [ $count -eq 0 ]; then
358		return 1
359	fi
360}
361
362trap 'on_error_exit "${FUNCNAME}" "${LINENO}"' ERR
363echo "INFO: JSON configuration test init"
364json_config_test_init
365
366tgt_rpc save_config > ${configs_path[target]}
367
368echo "INFO: shutting down applications..."
369if [[ $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
370	initiator_rpc save_config > ${configs_path[initiator]}
371	json_config_clear initiator
372	json_config_test_shutdown_app initiator
373fi
374
375json_config_clear target
376json_config_test_shutdown_app target
377
378echo "INFO: relaunching applications..."
379json_config_test_start_app target --json ${configs_path[target]}
380if [[ $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
381	json_config_test_start_app initiator --json ${configs_path[initiator]}
382fi
383
384echo "INFO: Checking if target configuration is the same..."
385$rootdir/test/json_config/json_diff.sh <(tgt_rpc save_config) "${configs_path[target]}"
386if [[ $SPDK_TEST_VHOST_INIT -eq 1 ]]; then
387	echo "INFO: Checking if virtio initiator configuration is the same..."
388	$rootdir/test/json_config/json_diff.sh <(initiator_rpc save_config) "${configs_path[initiator]}"
389fi
390
391echo "INFO: changing configuration and checking if this can be detected..."
392# Self test to check if configuration diff can be detected.
393tgt_rpc bdev_malloc_delete MallocBdevForConfigChangeCheck
394if $rootdir/test/json_config/json_diff.sh <(tgt_rpc save_config) "${configs_path[target]}" > /dev/null; then
395	echo "ERROR: intentional configuration difference not detected!"
396	false
397else
398	echo "INFO: configuration change detected."
399fi
400
401json_config_test_fini
402
403echo "INFO: Success"
404