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