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