xref: /spdk/test/sma/crypto.sh (revision 34edd9f1bf5fda4c987f4500ddc3c9f50be32e7d)
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 --wait-for-rpc &
148hostpid=$!
149
150waitforlisten $hostpid
151
152# Configure host with accel crypto parameters
153$rpc_py dpdk_cryptodev_scan_accel_module
154rpc_cmd dpdk_cryptodev_set_driver -d crypto_aesni_mb
155$rpc_py accel_assign_opc -o encrypt -m dpdk_cryptodev
156$rpc_py accel_assign_opc -o decrypt -m dpdk_cryptodev
157$rpc_py framework_start_init
158
159"$rootdir/build/bin/spdk_tgt" -r "$tgtsock" -m 0x2 &
160tgtpid=$!
161
162$rootdir/scripts/sma.py -c <(
163	cat <<- CONFIG
164		address: 127.0.0.1
165		port: 8080
166		devices:
167		  - name: 'nvmf_tcp'
168		crypto:
169		  name: 'bdev_crypto'
170	CONFIG
171) &
172smapid=$!
173
174# Wait until the SMA starts listening
175sma_waitforlisten
176
177# Prepare the target
178uuid=$(uuidgen)
179waitforlisten "$tgtpid" "$tgtsock"
180$rpc_py -s "$tgtsock" << CONFIG
181	bdev_malloc_create -b malloc0 32 4096 -u $uuid
182	nvmf_create_transport -t tcp
183	nvmf_create_subsystem $tgtnqn -a
184	nvmf_subsystem_add_listener discovery -t tcp -a 127.0.0.1 -s $discovery_port
185	nvmf_subsystem_add_listener -t tcp -a 127.0.0.1 -s 4421 -f ipv4 $tgtnqn
186	nvmf_subsystem_add_ns $tgtnqn malloc0
187CONFIG
188
189# Create an empty device first
190device=$(create_device | jq -r '.handle')
191
192# First attach a volume without crypto
193attach_volume $device $uuid
194
195ns_bdev=$(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].name')
196[[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == 'NVMe disk' ]]
197[[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 0 ]]
198[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].uuid') == "$uuid" ]]
199[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces[0].nguid') == "$(uuid2nguid $uuid)" ]]
200
201detach_volume $device $uuid
202
203# Now attach a volume with crypto enabled
204attach_volume $device $uuid AES_CBC $key0
205
206[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]]
207[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]]
208# Make sure that the namespace exposed in the subsystem is a crypto bdev and is using malloc bdev's UUID
209verify_crypto_volume $localnqn $uuid
210# Check that it's using correct key
211crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")')
212key_name=$(jq -r '.driver_specific.crypto.key_name' <<< "$crypto_bdev")
213key_obj=$(rpc_cmd accel_crypto_keys_get -k $key_name)
214[[ $(jq -r '.[0].key' <<< "$key_obj") == "$key0" ]]
215[[ $(jq -r '.[0].cipher' <<< "$key_obj") == "AES_CBC" ]]
216
217# Attach the same volume again
218attach_volume $device $uuid AES_CBC $key0
219
220# Nothing should change
221[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 1 ]]
222[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 1 ]]
223verify_crypto_volume $localnqn $uuid
224crypto_bdev2=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")')
225[[ $(jq -r '.name' <<< "$crypto_bdev") == $(jq -r '.name' <<< "$crypto_bdev2") ]]
226key_name=$(jq -r '.driver_specific.crypto.key_name' <<< "$crypto_bdev2")
227key_obj=$(rpc_cmd accel_crypto_keys_get -k $key_name)
228[[ $(jq -r '.[0].key' <<< "$key_obj") == "$key0" ]]
229[[ $(jq -r '.[0].cipher' <<< "$key_obj") == "AES_CBC" ]]
230
231# Try to do attach it again, but this time use a different crypto algorithm
232NOT attach_volume $device $uuid AES_XTS $key0
233# Check the same, this time changing the key
234NOT attach_volume $device $uuid AES_CBC $key1
235# Check the same, this time adding second key
236NOT attach_volume $device $uuid AES_CBC $key0 $key1
237# Check out-of-range cipher value
238NOT attach_volume $device $uuid 8 $key0
239
240# Make sure these failures haven't affected anything
241verify_crypto_volume $localnqn $uuid
242
243detach_volume $device $uuid
244
245# Check that if there's something wrong with crypto params, the volume won't get attached and
246# everything is cleaned up afterwards
247NOT attach_volume $device $uuid 8 $key0
248[[ $(rpc_cmd nvmf_get_subsystems $localnqn | jq -r '.[0].namespaces | length') -eq 0 ]]
249[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
250[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
251
252delete_device $device
253
254# Check that it's possible to create a device immediately specifying a volume with crypto
255device=$(create_device $uuid AES_CBC $key0 | jq -r '.handle')
256verify_crypto_volume $localnqn $uuid
257
258detach_volume $device $uuid
259delete_device $device
260
261# Try to create a device with incorrect volume crypto params, check that it fails and everything
262# is cleaned up afterwards
263NOT create_device $uuid 8 $key0
264[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
265[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
266[[ $(rpc_cmd nvmf_get_subsystems | jq -r "[.[] | select(.nqn == \"$localnqn\")] | length") -eq 0 ]]
267
268# Check that if crypto is disabled, it's not possible to attach a volume with crypto
269killprocess $smapid
270$rootdir/scripts/sma.py -c <(
271	cat <<- CONFIG
272		address: 127.0.0.1
273		port: 8080
274		devices:
275		  - name: 'nvmf_tcp'
276	CONFIG
277) &
278smapid=$!
279
280sma_waitforlisten
281device=$(create_device | jq -r '.handle')
282
283NOT attach_volume $device $uuid AES_CBC $key0
284[[ $(rpc_cmd bdev_nvme_get_discovery_info | jq -r '. | length') -eq 0 ]]
285[[ $(rpc_cmd bdev_get_bdevs | jq -r length) -eq 0 ]]
286
287cleanup
288trap - SIGINT SIGTERM EXIT
289