Spdk/test/sma/vfiouser_qemu.sh

367 lines
11 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2022 Intel Corporation
# All rights reserved.
#
testdir=$(readlink -f "$(dirname "$0")")
rootdir=$(readlink -f "$testdir/../..")
source "$rootdir/test/common/autotest_common.sh"
source "$rootdir/test/vfio_user/common.sh"
source "$testdir/common.sh"
function create_device() {
local pfid=${1:-1}
local vfid=${2:-0}
"$rootdir/scripts/sma-client.py" <<- CREATE
{
"method": "CreateDevice",
"params": {
"nvme": {
"physical_id": "$pfid",
"virtual_id": "$vfid"
}
}
}
CREATE
}
function delete_device() {
"$rootdir/scripts/sma-client.py" <<- DELETE
{
"method": "DeleteDevice",
"params": {
"handle": "$1"
}
}
DELETE
}
function attach_volume() {
"$rootdir/scripts/sma-client.py" <<- ATTACH
{
"method": "AttachVolume",
"params": {
"device_handle": "$1",
"volume": {
"volume_id": "$(uuid2base64 $2)"
}
}
}
ATTACH
}
function detach_volume() {
"$rootdir/scripts/sma-client.py" <<- DETACH
{
"method": "DetachVolume",
"params": {
"device_handle": "$1",
"volume_id": "$(uuid2base64 $2)"
}
}
DETACH
}
function vm_count_nvme() {
vm_exec $1 "grep -l SPDK /sys/class/nvme/*/model" | wc -l
}
function vm_check_subsys_volume() {
local vm_id=$1
local nqn=$2
local uuid=$3
nvme="$(vm_exec $vm_id "grep -l $nqn /sys/class/nvme/*/subsysnqn" | awk -F/ '{print $5}')"
if [[ -z "$nvme" ]]; then
error "FAILED no NVMe on vm=$vm_id with nqn=$nqn"
return 1
fi
tmpuuid="$(vm_exec $vm_id "grep -l $uuid /sys/class/nvme/$nvme/nvme*/uuid")"
if [[ -z "$tmpuuid" ]]; then
return 1
fi
}
function vm_check_subsys_nqn() {
sleep 1
nqn=$(vm_exec $1 "grep -l $2 /sys/class/nvme/*/subsysnqn")
if [[ -z "$nqn" ]]; then
error "FAILED no NVMe on vm=$1 with nqn=$2"
return 1
fi
}
function cleanup() {
vm_kill_all
killprocess $tgtpid
killprocess $smapid
if [ -e "${VFO_ROOT_PATH}" ]; then rm -rf "${VFO_ROOT_PATH}"; fi
}
trap "cleanup; exit 1" SIGINT SIGTERM EXIT
# SSH VM Password
VM_PASSWORD=root
vm_no=0
VFO_ROOT_PATH="/tmp/sma/vfio-user/qemu"
if [ -e "${VFO_ROOT_PATH}" ]; then rm -rf "${VFO_ROOT_PATH}"; fi
mkdir -p "${VFO_ROOT_PATH}"
# Cleanup old VM:
used_vms=$vm_no
vm_kill_all
vm_setup --os="$VM_IMAGE" --disk-type=virtio --force=$vm_no --qemu-args="-qmp tcp:localhost:10005,server,nowait \
-device pci-bridge,chassis_nr=1,id=pci.spdk.0 \
-device pci-bridge,chassis_nr=2,id=pci.spdk.1"
# Run pre-configured VM and wait for them to start
vm_run $vm_no
vm_wait_for_boot 300 $vm_no
# Start SPDK
$rootdir/build/bin/spdk_tgt &
tgtpid=$!
waitforlisten $tgtpid
# Prepare the target
rpc_cmd bdev_null_create null0 100 4096
rpc_cmd bdev_null_create null1 100 4096
# Start SMA server
$rootdir/scripts/sma.py -c <(
cat <<- EOF
devices:
- name: 'vfiouser'
params:
buses:
- name: 'pci.spdk.0'
count: 32
- name: 'pci.spdk.1'
count: 32
qmp_addr: 127.0.0.1
qmp_port: 10005
crypto:
name: 'bdev_crypto'
params:
driver: 'crypto_aesni_mb'
EOF
) &
smapid=$!
# Wait until the SMA starts listening
sma_waitforlisten
# Make sure a TCP transport has been created
rpc_cmd nvmf_get_transports --trtype VFIOUSER
# Make sure no nvme subsystems are present
[[ $(vm_exec ${vm_no} nvme list-subsys -o json | jq -r '.Subsystems | length') -eq 0 ]]
# Create a couple of devices and verify them via RPC and SSH
device0=$(create_device 0 0 | jq -r '.handle')
rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0
vm_check_subsys_nqn $vm_no nqn.2016-06.io.spdk:vfiouser-0
# Check that there are two subsystems (1 created above + discovery)
[[ $(rpc_cmd nvmf_get_subsystems | jq -r '. | length') -eq 2 ]]
device1=$(create_device 1 0 | jq -r '.handle')
rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0
rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1
[[ "$device0" != "$device1" ]]
vm_check_subsys_nqn $vm_no nqn.2016-06.io.spdk:vfiouser-1
# Check that there are three subsystems (2 created above + discovery)
[[ $(rpc_cmd nvmf_get_subsystems | jq -r '. | length') -eq 3 ]]
# Verify the method is idempotent and sending the same gRPCs won't create new
# devices and will return the same IDs
tmp0=$(create_device 0 0 | jq -r '.handle')
tmp1=$(create_device 1 0 | jq -r '.handle')
[[ $(vm_count_nvme ${vm_no}) -eq 2 ]]
[[ $(rpc_cmd nvmf_get_subsystems | jq -r '. | length') -eq 3 ]]
[[ "$tmp0" == "$device0" ]]
[[ "$tmp1" == "$device1" ]]
# Now remove them verifying via RPC
delete_device "$device0"
NOT rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0
rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1
[[ $(rpc_cmd nvmf_get_subsystems | jq -r '. | length') -eq 2 ]]
[[ $(vm_count_nvme ${vm_no}) -eq 1 ]]
delete_device "$device1"
NOT rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0
NOT rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1
[[ $(rpc_cmd nvmf_get_subsystems | jq -r '. | length') -eq 1 ]]
[[ $(vm_count_nvme ${vm_no}) -eq 0 ]]
# Finally check that removing a non-existing device is also successful
delete_device "$device0"
delete_device "$device1"
# Check volume attach/detach
device0=$(create_device 0 0 | jq -r '.handle')
device1=$(create_device 1 0 | jq -r '.handle')
uuid0=$(rpc_cmd bdev_get_bdevs -b null0 | jq -r '.[].uuid')
uuid1=$(rpc_cmd bdev_get_bdevs -b null1 | jq -r '.[].uuid')
# Attach the first volume to a first subsystem
attach_volume "$device0" "$uuid0"
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces | length') -eq 0 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces[0].uuid') == "$uuid0" ]]
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid0
attach_volume "$device1" "$uuid1"
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces[0].uuid') == "$uuid0" ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces[0].uuid') == "$uuid1" ]]
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid1
# Attach the same device again and see that it won't fail
attach_volume "$device0" "$uuid0"
attach_volume "$device1" "$uuid1"
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces[0].uuid') == "$uuid0" ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces[0].uuid') == "$uuid1" ]]
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid0
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid1
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid1
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid0
# Cross detach volumes and verify they not fail and have not been removed from the subsystems
detach_volume "$device0" "$uuid1"
detach_volume "$device1" "$uuid0"
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces | length') -eq 1 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces[0].uuid') == "$uuid0" ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces[0].uuid') == "$uuid1" ]]
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid0
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid1
vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid1
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid0
# Detach volumes and verify they have been removed from the subsystems
detach_volume "$device0" "$uuid0"
detach_volume "$device1" "$uuid1"
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces | length') -eq 0 ]]
[[ $(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-1 | jq -r '.[0].namespaces | length') -eq 0 ]]
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-0 $uuid0
NOT vm_check_subsys_volume $vm_no nqn.2016-06.io.spdk:vfiouser-1 $uuid1
# Detach volumes once again and verify they will not fail
detach_volume "$device0" "$uuid0"
detach_volume "$device1" "$uuid1"
detach_volume "$device0" "$uuid1"
detach_volume "$device1" "$uuid0"
delete_device "$device0"
delete_device "$device1"
# Create device with allocation on second bus
device3=$(create_device 42 0 | jq -r '.handle')
vm_check_subsys_nqn $vm_no nqn.2016-06.io.spdk:vfiouser-42
# Verify that device can be found on second bus and properly deleted
delete_device "$device3"
NOT vm_check_subsys_nqn $vm_no nqn.2016-06.io.spdk:vfiouser-42
key0=1234567890abcdef1234567890abcdef
device0=$(create_device 0 0 | jq -r '.handle')
uuid0=$(rpc_cmd bdev_get_bdevs -b null0 | jq -r '.[].uuid')
# Now check vfio-user attach with bdev crypto
"$rootdir/scripts/sma-client.py" <<- ATTACH
{
"method": "AttachVolume",
"params": {
"device_handle": "$device0",
"volume": {
"volume_id": "$(uuid2base64 $uuid0)",
"crypto": {
"cipher": "$(get_cipher AES_CBC)",
"key": "$(format_key $key0)"
}
}
}
}
ATTACH
# Make sure that the namespace exposed in the subsystem is a crypto bdev
ns_bdev=$(rpc_cmd nvmf_get_subsystems nqn.2016-06.io.spdk:vfiouser-0 | jq -r '.[0].namespaces[0].name')
[[ $(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[0].product_name') == "crypto" ]]
crypto_bdev=$(rpc_cmd bdev_get_bdevs -b "$ns_bdev" | jq -r '.[] | select(.product_name == "crypto")')
[[ $(rpc_cmd bdev_get_bdevs | jq -r '[.[] | select(.product_name == "crypto")] | length') -eq 1 ]]
[[ $(jq -r '.driver_specific.crypto.key' <<< "$crypto_bdev") == "$key0" ]]
detach_volume "$device0" "$uuid0"
delete_device "$device0"
[[ $(rpc_cmd bdev_get_bdevs | jq -r '.[] | select(.product_name == "crypto")' | jq -r length) -eq 0 ]]
# Test qos
device_vfio_user=1
device0=$(create_device 0 0 | jq -r '.handle')
attach_volume "$device0" "$uuid0"
# First check the capabilities
diff <(get_qos_caps $device_vfio_user | jq --sort-keys) <(
jq --sort-keys <<- CAPS
{
"max_volume_caps": {
"rw_iops": true,
"rd_bandwidth": true,
"wr_bandwidth": true,
"rw_bandwidth": true
}
}
CAPS
)
"$rootdir/scripts/sma-client.py" <<- EOF
{
"method": "SetQos",
"params": {
"device_handle": "$device0",
"volume_id": "$(uuid2base64 $uuid0)",
"maximum": {
"rd_iops": 0,
"wr_iops": 0,
"rw_iops": 3,
"rd_bandwidth": 4,
"wr_bandwidth": 5,
"rw_bandwidth": 6
}
}
}
EOF
# Make sure that limits were changed
diff <(rpc_cmd bdev_get_bdevs -b null0 | jq --sort-keys '.[].assigned_rate_limits') <(
jq --sort-keys <<- EOF
{
"rw_ios_per_sec": 3000,
"rw_mbytes_per_sec": 6,
"r_mbytes_per_sec": 4,
"w_mbytes_per_sec": 5
}
EOF
)
detach_volume "$device0" "$uuid0"
delete_device "$device0"
cleanup
trap - SIGINT SIGTERM EXIT