1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2022 Intel Corporation 4# All rights reserved. 5# 6 7testdir=$(readlink -f "$(dirname "$0")") 8rootdir=$(readlink -f "$testdir/../..") 9 10source "$rootdir/test/common/autotest_common.sh" 11source "$testdir/common.sh" 12 13rpc_py="$rootdir/scripts/rpc.py" 14localnqn=nqn.2016-06.io.spdk:cnode0 15tgtnqn=nqn.2016-06.io.spdk:tgt0 16key0=1234567890abcdef1234567890abcdef 17key1=deadbeefcafebabefeedbeefbabecafe 18tgtsock=/var/tmp/spdk.sock2 19discovery_port=8009 20 21cleanup() { 22 killprocess $smapid 23 killprocess $hostpid 24 killprocess $tgtpid 25} 26 27gen_volume_params() { 28 local volume_id=$1 cipher=$2 key=$3 key2=$4 config 29 local -a params crypto 30 31 config=$( 32 cat <<- PARAMS 33 "volume_id": "$(uuid2base64 $volume_id)", 34 "nvmf": { 35 "hostnqn": "nqn.2016-06.io.spdk:host0", 36 "discovery": { 37 "discovery_endpoints": [ 38 { 39 "trtype": "tcp", 40 "traddr": "127.0.0.1", 41 "trsvcid": "$discovery_port" 42 } 43 ] 44 } 45 } 46 PARAMS 47 ) 48 params+=("$config") 49 50 local IFS="," 51 if [[ -n "$cipher" ]]; then 52 crypto+=("\"cipher\": $(get_cipher $cipher)") 53 crypto+=("\"key\": \"$(format_key $key)\"") 54 if [[ -n "$key2" ]]; then 55 crypto+=("\"key2\": \"$(format_key $key2)\"") 56 fi 57 58 crypto_config=$( 59 cat <<- PARAMS 60 "crypto": { 61 ${crypto[*]} 62 } 63 PARAMS 64 ) 65 66 params+=("$crypto_config") 67 fi 68 69 cat <<- PARAMS 70 "volume": { 71 ${params[*]} 72 } 73 PARAMS 74} 75 76create_device() { 77 "$rootdir/scripts/sma-client.py" <<- CREATE 78 { 79 "method": "CreateDevice", 80 "params": { 81 "nvmf_tcp": { 82 "subnqn": "$localnqn", 83 "adrfam": "ipv4", 84 "traddr": "127.0.0.1", 85 "trsvcid": "4420" 86 } 87 ${1:+, $(gen_volume_params "$@")} 88 } 89 } 90 CREATE 91} 92 93delete_device() { 94 "$rootdir/scripts/sma-client.py" <<- DELETE 95 { 96 "method": "DeleteDevice", 97 "params": { 98 "handle": "$1" 99 } 100 } 101 DELETE 102} 103 104attach_volume() { 105 local device=$1 106 shift 107 108 "$rootdir/scripts/sma-client.py" <<- ATTACH 109 { 110 "method": "AttachVolume", 111 "params": { 112 "device_handle": "$device", 113 $(gen_volume_params "$@") 114 } 115 } 116 ATTACH 117} 118 119detach_volume() { 120 "$rootdir/scripts/sma-client.py" <<- DETACH 121 { 122 "method": "DetachVolume", 123 "params": { 124 "device_handle": "$1", 125 "volume_id": "$(uuid2base64 $2)" 126 } 127 } 128 DETACH 129} 130 131verify_crypto_volume() { 132 local nqn=$1 uuid=$2 ns ns_bdev 133 134 ns=$(rpc_cmd nvmf_get_subsystems $nqn | jq -r '.[0].namespaces[0]') 135 ns_bdev=$(jq -r '.name' <<< "$ns") 136 137 # Make sure that the namespace is a crypto bdev and that there's only a single crypto bdev 138 [[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == crypto ]] 139 [[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 1 ]] 140 # Check that the namespace's UUID/NGUID matches the one requested by the user 141 [[ $(jq -r '.uuid' <<< "$ns") == "$uuid" ]] 142 [[ $(jq -r '.nguid' <<< "$ns") == "$(uuid2nguid $uuid)" ]] 143} 144 145trap "cleanup; exit 1" SIGINT SIGTERM EXIT 146 147"$rootdir/build/bin/spdk_tgt" -m 0x1 & 148hostpid=$! 149 150"$rootdir/build/bin/spdk_tgt" -r "$tgtsock" -m 0x2 & 151tgtpid=$! 152 153$rootdir/scripts/sma.py -c <( 154 cat <<- CONFIG 155 address: 127.0.0.1 156 port: 8080 157 devices: 158 - name: 'nvmf_tcp' 159 crypto: 160 name: 'bdev_crypto' 161 params: 162 driver: 'crypto_aesni_mb' 163 CONFIG 164) & 165smapid=$! 166 167# Wait until the SMA starts listening 168sma_waitforlisten 169 170# Prepare the target 171uuid=$(uuidgen) 172waitforlisten "$tgtpid" "$tgtsock" 173$rpc_py -s "$tgtsock" << CONFIG 174 bdev_malloc_create -b malloc0 32 4096 -u $uuid 175 nvmf_create_transport -t tcp 176 nvmf_create_subsystem $tgtnqn -a 177 nvmf_subsystem_add_listener discovery -t tcp -a 127.0.0.1 -s $discovery_port 178 nvmf_subsystem_add_listener -t tcp -a 127.0.0.1 -s 4421 -f ipv4 $tgtnqn 179 nvmf_subsystem_add_ns $tgtnqn malloc0 180CONFIG 181 182# Create an empty device first 183device=$(create_device | jq -r '.handle') 184 185# First attach a volume without crypto 186attach_volume $device $uuid 187 188ns_bdev=$(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].name') 189[[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == 'NVMe disk' ]] 190[[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 0 ]] 191[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].uuid') == "$uuid" ]] 192[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].nguid') == "$(uuid2nguid $uuid)" ]] 193 194detach_volume $device $uuid 195 196# Now attach a volume with crypto enabled 197attach_volume $device $uuid AES_CBC $key0 198 199[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]] 200[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]] 201# Make sure that the namespace exposed in the subsystem is a crypto bdev and is using malloc bdev's UUID 202verify_crypto_volume $localnqn $uuid 203# Check that it's using correct key 204crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")') 205[[ $(jq -r '.driver_specific.crypto.key' <<< "$crypto_bdev") == "$key0" ]] 206 207# Attach the same volume again 208attach_volume $device $uuid AES_CBC $key0 209 210# Nothing should change 211[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]] 212[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]] 213verify_crypto_volume $localnqn $uuid 214crypto_bdev2=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")') 215[[ $(jq -r '.name' <<< "$crypto_bdev") == $(jq -r '.name' <<< "$crypto_bdev2") ]] 216[[ $(jq -r '.driver_specific.crypto.key' <<< "$crypto_bdev2") == "$key0" ]] 217 218# Try to do attach it again, but this time use a different crypto algorithm 219NOT attach_volume $device $uuid AES_XTS $key0 220# Check the same, this time changing the key 221NOT attach_volume $device $uuid AES_CBC $key1 222# Check the same, this time adding second key 223NOT attach_volume $device $uuid AES_CBC $key0 $key1 224# Check out-of-range cipher value 225NOT attach_volume $device $uuid 8 $key0 226 227# Make sure these failures haven't affected anything 228verify_crypto_volume $localnqn $uuid 229 230detach_volume $device $uuid 231 232# Check that if there's something wrong with crypto params, the volume won't get attached and 233# everything is cleaned up afterwards 234NOT attach_volume $device $uuid 8 $key0 235[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 0 ]] 236[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]] 237[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]] 238 239delete_device $device 240 241# Check that it's possible to create a device immediately specyfing a volume with crypto 242device=$(create_device $uuid AES_CBC $key0 | jq -r '.handle') 243verify_crypto_volume $localnqn $uuid 244 245delete_device $device 246 247# Try to create a device with incorrect volume crypto params, check that it fails and everything 248# is cleaned up afterwards 249NOT create_device $uuid 8 $key0 250[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]] 251[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]] 252[[ $(rpc_cmd nvmf_get_subsystems | jq -r "[.[] | select(.nqn == \"$localnqn\")] | length") -eq 0 ]] 253 254# Check that if crypto is disabled, it's not possible to attach a volume with crypto 255killprocess $smapid 256$rootdir/scripts/sma.py -c <( 257 cat <<- CONFIG 258 address: 127.0.0.1 259 port: 8080 260 devices: 261 - name: 'nvmf_tcp' 262 CONFIG 263) & 264smapid=$! 265 266sma_waitforlisten 267device=$(create_device | jq -r '.handle') 268 269NOT attach_volume $device $uuid AES_CBC $key0 270[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]] 271[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]] 272 273cleanup 274trap - SIGINT SIGTERM EXIT 275