xref: /spdk/test/sma/vhost_blk.sh (revision c6c1234de9e0015e670dd0b51bf6ce39ee0e07bd)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2022 Intel Corporation
4#  All rights reserved.
5#
6testdir=$(readlink -f "$(dirname "$0")")
7rootdir=$(readlink -f "$testdir/../..")
8
9source "$rootdir/test/common/autotest_common.sh"
10source "$rootdir/test/vhost/common.sh"
11source "$testdir/common.sh"
12
13function cleanup() {
14	killprocess $vhostpid
15	killprocess $smapid
16	vm_kill_all
17}
18
19function create_device() {
20	"$rootdir/scripts/sma-client.py" <<- CREATE
21		{
22		  "method": "CreateDevice",
23		  "params": {
24		    "virtio_blk": {
25		      "physical_id": "$1",
26		      "virtual_id": "0"
27		    },
28		    "volume": {
29		      "volume_id": "$(uuid2base64 $2)"
30		    }
31		  }
32		}
33	CREATE
34}
35
36function delete_device() {
37	"$rootdir/scripts/sma-client.py" <<- DELETE
38		{
39		  "method": "DeleteDevice",
40		  "params": {
41		    "handle": "$1"
42		  }
43		}
44	DELETE
45}
46
47trap "cleanup; exit 1" SIGINT SIGTERM EXIT
48
49vm_no=0
50bus_size=32
51
52timing_enter setup_vm
53vm_setup \
54	--force=$vm_no \
55	--disk-type=virtio \
56	--qemu-args="-qmp tcp:localhost:9090,server,nowait -device pci-bridge,chassis_nr=1,id=pci.spdk.0 -device pci-bridge,chassis_nr=2,id=pci.spdk.1" \
57	--os="$VM_IMAGE"
58
59vm_run $vm_no
60vm_wait_for_boot 300 $vm_no
61timing_exit setup_vm
62
63$rootdir/build/bin/vhost -S /var/tmp -m 0x3 --wait-for-rpc &
64vhostpid=$!
65
66waitforlisten $vhostpid
67
68# Configure accel crypto module & operations
69rpc_cmd dpdk_cryptodev_scan_accel_module
70rpc_cmd dpdk_cryptodev_set_driver -d crypto_aesni_mb
71rpc_cmd accel_assign_opc -o encrypt -m dpdk_cryptodev
72rpc_cmd accel_assign_opc -o decrypt -m dpdk_cryptodev
73rpc_cmd framework_start_init
74
75$rootdir/scripts/sma.py -c <(
76	cat <<- EOF
77		address: 127.0.0.1
78		port: 8080
79		devices:
80		  - name: 'vhost_blk'
81		    params:
82		      buses:
83		      - name: 'pci.spdk.0'
84		        count: $bus_size
85		      - name: 'pci.spdk.1'
86		        count: $bus_size
87		      qmp_addr: 127.0.0.1
88		      qmp_port: 9090
89		crypto:
90		  name: 'bdev_crypto'
91	EOF
92) &
93smapid=$!
94
95# Wait until the SMA starts listening
96sma_waitforlisten
97
98# Check that there is no vhost device on guest os
99[[ $(vm_exec $vm_no "lsblk | grep -E \"^vd.\" | wc -l") -eq 0 ]]
100
101# Prepare the target
102rpc_cmd bdev_null_create null0 100 4096
103rpc_cmd bdev_null_create null1 100 4096
104uuid=$(rpc_cmd bdev_get_bdevs -b null0 | jq -r '.[].uuid')
105uuid2=$(rpc_cmd bdev_get_bdevs -b null1 | jq -r '.[].uuid')
106
107# Create a couple of devices and verify them via RPC
108devid0=$(create_device 0 $uuid | jq -r '.handle')
109rpc_cmd vhost_get_controllers -n sma-0
110
111devid1=$(create_device 1 $uuid2 | jq -r '.handle')
112rpc_cmd vhost_get_controllers -n sma-0
113rpc_cmd vhost_get_controllers -n sma-1
114[[ "$devid0" != "$devid1" ]]
115
116# Check that there are two controllers (2 created above )
117[[ $(rpc_cmd vhost_get_controllers | jq -r '. | length') -eq 2 ]]
118
119# Verify the method is idempotent and sending the same gRPCs won't create new
120# devices and will return the same handles
121tmp0=$(create_device 0 $uuid | jq -r '.handle')
122tmp1=$(create_device 1 $uuid2 | jq -r '.handle')
123
124# Try to duplicate device, this time with different uuid
125NOT create_device 1 $uuid | jq -r '.handle'
126
127# Check that there are execly two vhost device on guest os
128[[ $(vm_exec $vm_no "lsblk | grep -E \"^vd.\" | wc -l") -eq 2 ]]
129
130[[ $(rpc_cmd vhost_get_controllers | jq -r '. | length') -eq 2 ]]
131[[ "$tmp0" == "$devid0" ]]
132[[ "$tmp1" == "$devid1" ]]
133
134# Now delete both of them verifying via RPC
135delete_device "$devid0"
136NOT rpc_cmd vhost_get_controllers -n sma-0
137[[ $(rpc_cmd vhost_get_controllers | jq -r '. | length') -eq 1 ]]
138
139delete_device "$devid1"
140NOT rpc_cmd vhost_get_controllers -n sma-1
141[[ $(rpc_cmd vhost_get_controllers | jq -r '. | length') -eq 0 ]]
142
143# Finally check that removing a non-existing device is also successful
144delete_device "$devid0"
145delete_device "$devid1"
146
147# At the end check if vhost devices are gone
148[[ $(vm_exec $vm_no "lsblk | grep -E \"^vd.\" | wc -l") -eq 0 ]]
149
150devids=()
151
152# Create two devices, one on each bus
153uuid=$(rpc_cmd bdev_get_bdevs -b null0 | jq -r '.[].uuid')
154devids[0]=$(create_device 0 $uuid | jq -r '.handle')
155uuid=$(rpc_cmd bdev_get_bdevs -b null1 | jq -r '.[].uuid')
156devids[1]=$(create_device $bus_size $uuid | jq -r '.handle')
157
158[[ $(vm_exec $vm_no "lsblk | grep -E \"^vd.\" | wc -l") -eq 2 ]]
159
160# Cleanup at the end
161for id in "${devids[@]}"; do
162	delete_device "$id"
163done
164
165# And back to none
166[[ $(vm_exec $vm_no "lsblk | grep -E \"^vd.\" | wc -l") -eq 0 ]]
167
168key0=1234567890abcdef1234567890abcdef
169rpc_cmd bdev_malloc_create -b malloc0 32 4096
170uuid=$(rpc_cmd bdev_get_bdevs -b malloc0 | jq -r '.[].uuid')
171
172# Try to create controller with bdev crypto
173devid0=$(
174	"$rootdir/scripts/sma-client.py" <<- CREATE | jq -r '.handle'
175		{
176		  "method": "CreateDevice",
177		  "params": {
178		    "virtio_blk": {
179		      "physical_id": "0",
180		      "virtual_id": "0"
181		    },
182		    "volume": {
183		      "volume_id": "$(uuid2base64 $uuid)",
184		      "crypto": {
185		        "cipher": "$(get_cipher AES_CBC)",
186		        "key": "$(format_key $key0)"
187		      }
188		    }
189		  }
190		}
191	CREATE
192)
193
194[[ $(rpc_cmd vhost_get_controllers | jq -r '. | length') -eq 1 ]]
195bdev=$(rpc_cmd vhost_get_controllers | jq -r '.[].backend_specific.block.bdev')
196
197crypto_bdev=$(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")')
198[[ $(jq -r '.driver_specific.crypto.name' <<< "$crypto_bdev") == "$bdev" ]]
199key_name=$(jq -r '.driver_specific.crypto.key_name' <<< "$crypto_bdev")
200key_obj=$(rpc_cmd accel_crypto_keys_get -k $key_name)
201[[ $(jq -r '.[0].key' <<< "$key_obj") == "$key0" ]]
202[[ $(jq -r '.[0].cipher' <<< "$key_obj") == "AES_CBC" ]]
203
204# Delete crypto device and check if it's gone
205delete_device $devid0
206[[ $(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")' | jq -r length) -eq 0 ]]
207
208# Test qos
209device_vhost=2
210uuid=$(rpc_cmd bdev_get_bdevs -b null0 | jq -r '.[].uuid')
211device=$(create_device 0 $uuid | jq -r '.handle')
212
213# First check the capabilities
214diff <(get_qos_caps $device_vhost | jq --sort-keys) <(
215	jq --sort-keys <<- CAPS
216		{
217		  "max_device_caps": {
218		    "rw_iops": true,
219		    "rd_bandwidth": true,
220		    "wr_bandwidth": true,
221		    "rw_bandwidth": true
222		  },
223		  "max_volume_caps": {
224		    "rw_iops": true,
225		    "rd_bandwidth": true,
226		    "wr_bandwidth": true,
227		    "rw_bandwidth": true
228		  }
229		}
230	CAPS
231)
232
233"$rootdir/scripts/sma-client.py" <<- EOF
234	{
235	  "method": "SetQos",
236	  "params": {
237	    "device_handle": "$device",
238	    "volume_id": "$(uuid2base64 $uuid)",
239	    "maximum": {
240	      "rd_iops": 0,
241	      "wr_iops": 0,
242	      "rw_iops": 3,
243	      "rd_bandwidth": 4,
244	      "wr_bandwidth": 5,
245	      "rw_bandwidth": 6
246	    }
247	  }
248	}
249EOF
250
251# Make sure that limits were changed
252diff <(rpc_cmd bdev_get_bdevs -b "$uuid" | jq --sort-keys '.[].assigned_rate_limits') <(
253	jq --sort-keys <<- EOF
254		{
255		  "rw_ios_per_sec": 3000,
256		  "rw_mbytes_per_sec": 6,
257		  "r_mbytes_per_sec": 4,
258		  "w_mbytes_per_sec": 5
259		}
260	EOF
261)
262
263# Try to set capabilities with empty volume id
264"$rootdir/scripts/sma-client.py" <<- EOF
265	{
266	  "method": "SetQos",
267	  "params": {
268	    "device_handle": "$device",
269	    "volume_id": "",
270	    "maximum": {
271	      "rd_iops": 0,
272	      "wr_iops": 0,
273	      "rw_iops": 4,
274	      "rd_bandwidth": 5,
275	      "wr_bandwidth": 6,
276	      "rw_bandwidth": 7
277	    }
278	  }
279	}
280EOF
281
282# Make sure that limits were changed even if volume id is not set
283diff <(rpc_cmd bdev_get_bdevs -b "$uuid" | jq --sort-keys '.[].assigned_rate_limits') <(
284	jq --sort-keys <<- EOF
285		{
286		  "rw_ios_per_sec": 4000,
287		  "rw_mbytes_per_sec": 7,
288		  "r_mbytes_per_sec": 5,
289		  "w_mbytes_per_sec": 6
290		}
291	EOF
292)
293
294# Try none-existing volume uuid
295NOT "$rootdir/scripts/sma-client.py" <<- EOF
296	{
297	  "method": "SetQos",
298	  "params": {
299	    "device_handle": "$device",
300	    "volume_id": "$(uuid2base64 $(uuidgen))",
301	    "maximum": {
302	      "rd_iops": 0,
303	      "wr_iops": 0,
304	      "rw_iops": 5,
305	      "rd_bandwidth": 6,
306	      "wr_bandwidth": 7,
307	      "rw_bandwidth": 8
308	    }
309	  }
310	}
311EOF
312
313# Try invalid (too short) volume uuid
314NOT "$rootdir/scripts/sma-client.py" <<- EOF
315	{
316	  "method": "SetQos",
317	  "params": {
318	    "device_handle": "$device",
319	    "volume_id": "$(base64 <<< 'invalid'))",
320	    "maximum": {
321	      "rd_iops": 0,
322	      "wr_iops": 0,
323	      "rw_iops": 5,
324	      "rd_bandwidth": 6,
325	      "wr_bandwidth": 7,
326	      "rw_bandwidth": 8
327	    }
328	  }
329	}
330EOF
331
332# Values remain unchanged
333diff <(rpc_cmd bdev_get_bdevs -b "$uuid" | jq --sort-keys '.[].assigned_rate_limits') <(
334	jq --sort-keys <<- EOF
335		{
336		  "rw_ios_per_sec": 4000,
337		  "rw_mbytes_per_sec": 7,
338		  "r_mbytes_per_sec": 5,
339		  "w_mbytes_per_sec": 6
340		}
341	EOF
342)
343
344delete_device "$device"
345
346cleanup
347trap - SIGINT SIGTERM EXIT
348