summaryrefslogtreecommitdiffstats
path: root/src/spdk/test/iscsi_tgt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/test/iscsi_tgt
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/test/iscsi_tgt')
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/bdev_io_wait/bdev_io_wait.sh50
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/calsoft/calsoft.py121
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/calsoft/calsoft.sh63
-rw-r--r--src/spdk/test/iscsi_tgt/calsoft/iscsi.json15
-rw-r--r--src/spdk/test/iscsi_tgt/calsoft/its.conf7
-rw-r--r--src/spdk/test/iscsi_tgt/common.sh209
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/digests/digests.sh94
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/ext4test/ext4test.sh131
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/filesystem/filesystem.sh145
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/fio/fio.sh150
-rw-r--r--src/spdk/test/iscsi_tgt/fio/iscsi.json32
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/fuzz/fuzz.sh65
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/initiator/initiator.sh52
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/ip_migration/ip_migration.sh131
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/iscsi_tgt.sh97
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/lvol/iscsi_lvol.sh85
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/multiconnection/multiconnection.sh84
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh99
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/perf/iscsi_initiator.sh37
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/perf/iscsi_target.sh134
-rw-r--r--src/spdk/test/iscsi_tgt/perf/perf.job19
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/pmem/iscsi_pmem.sh74
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/qos/qos.sh145
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/rbd/rbd.sh72
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/reset/reset.sh77
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/rpc_config/rpc_config.py481
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/rpc_config/rpc_config.sh63
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/sock/sock.sh142
-rwxr-xr-xsrc/spdk/test/iscsi_tgt/trace_record/trace_record.sh135
29 files changed, 3009 insertions, 0 deletions
diff --git a/src/spdk/test/iscsi_tgt/bdev_io_wait/bdev_io_wait.sh b/src/spdk/test/iscsi_tgt/bdev_io_wait/bdev_io_wait.sh
new file mode 100755
index 000000000..15dfe1165
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/bdev_io_wait/bdev_io_wait.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+iscsitestinit $1 $2
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+
+rpc_py="$rootdir/scripts/rpc.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m 0x2 -p 1 -s 512 --wait-for-rpc &
+pid=$!
+echo "iSCSI target launched. pid: $pid"
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 4
+# Minimal number of bdev io pool (5) and cache (1)
+$rpc_py bdev_set_options -p 5 -c 1
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "Malloc0:0" ==> use Malloc0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node disk1 disk1_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 256 -d
+sleep 1
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+"$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w write -t 1
+"$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w read -t 1
+"$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w flush -t 1
+"$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w unmap -t 1
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $pid
+
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/calsoft/calsoft.py b/src/spdk/test/iscsi_tgt/calsoft/calsoft.py
new file mode 100755
index 000000000..5be658e61
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/calsoft/calsoft.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+
+import os
+import time
+import sys
+import subprocess
+import threading
+import json
+
+CALSOFT_BIN_PATH = "/usr/local/calsoft/iscsi-pcts-v1.5/bin"
+
+'''
+11/26/2015 disable tc_login_11_2 and tc_login_11_4
+RFC 7143 6.3
+Neither the initiator nor the target should attempt to declare or
+negotiate a parameter more than once during login, except for
+responses to specific keys that explicitly allow repeated key
+declarations (e.g., TargetAddress)
+
+The spec didn't make it clear what other keys could be re-declare
+Disscussed this with UNH and get the conclusion that TargetName/
+TargetAddress/MaxRecvDataSegmentLength could be re-declare.
+'''
+'''
+12/1/2015 add tc_login_2_2 to known_failed_cases
+RFC 7143 6.1
+A standard-label MUST begin with a capital letter and must not exceed
+63 characters.
+key name: A standard-label
+'''
+'''
+06/10/2020 add tc_login_29_1 to known_failed_cases
+RFC 3720 12.19. DataSequenceInOrder
+Irrelevant when: SessionType=Discovery
+'''
+
+known_failed_cases = ['tc_ffp_15_2', 'tc_ffp_29_2', 'tc_ffp_29_3', 'tc_ffp_29_4',
+ 'tc_err_1_1', 'tc_err_1_2', 'tc_err_2_8',
+ 'tc_err_3_1', 'tc_err_3_2', 'tc_err_3_3',
+ 'tc_err_3_4', 'tc_err_5_1', 'tc_login_3_1',
+ 'tc_login_11_2', 'tc_login_11_4', 'tc_login_2_2', 'tc_login_29_1']
+
+
+def run_case(case, result_list, log_dir_path):
+ try:
+ case_log = subprocess.check_output("{}/{}".format(CALSOFT_BIN_PATH, case), stderr=subprocess.STDOUT, shell=True).decode('utf-8')
+ except subprocess.CalledProcessError as e:
+ result_list.append({"Name": case, "Result": "FAIL"})
+ case_log = e.output.decode('utf-8')
+ else:
+ result_list.append({"Name": case, "Result": "PASS"})
+ with open(log_dir_path + case + '.txt', 'w') as f:
+ f.write(case_log)
+
+
+def main():
+ if not os.path.exists(CALSOFT_BIN_PATH):
+ print("The Calsoft test suite is not available on this machine.")
+ sys.exit(1)
+
+ output_dir = sys.argv[1]
+ if len(sys.argv) > 2:
+ output_file = sys.argv[2]
+ else:
+ output_file = "%s/calsoft.json" % (output_dir)
+
+ log_dir = "%s/calsoft/" % output_dir
+
+ all_cases = [x for x in os.listdir(CALSOFT_BIN_PATH) if x.startswith('tc')]
+ all_cases.sort()
+
+ case_result_list = []
+
+ result = {"Calsoft iSCSI tests": case_result_list}
+
+ if not os.path.exists(log_dir):
+ os.mkdir(log_dir)
+ for case in known_failed_cases:
+ print("Skipping %s. It is known to fail." % (case))
+ case_result_list.append({"Name": case, "Result": "SKIP"})
+
+ thread_objs = []
+ left_cases = list(set(all_cases) - set(known_failed_cases))
+ index = 0
+ max_thread_count = 32
+
+ while index < len(left_cases):
+ cur_thread_count = 0
+ for thread_obj in thread_objs:
+ if thread_obj.is_alive():
+ cur_thread_count += 1
+ while cur_thread_count < max_thread_count and index < len(left_cases):
+ thread_obj = threading.Thread(target=run_case, args=(left_cases[index], case_result_list, log_dir, ))
+ thread_obj.start()
+ time.sleep(0.02)
+ thread_objs.append(thread_obj)
+ index += 1
+ cur_thread_count += 1
+ end_time = time.time() + 30
+ while time.time() < end_time:
+ for thread_obj in thread_objs:
+ if thread_obj.is_alive():
+ break
+ else:
+ break
+ else:
+ print("Thread timeout")
+ exit(1)
+ with open(output_file, 'w') as f:
+ json.dump(obj=result, fp=f, indent=2)
+
+ failed = 0
+ for x in case_result_list:
+ if x["Result"] == "FAIL":
+ print("Test case %s failed." % (x["Name"]))
+ failed = 1
+ exit(failed)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/spdk/test/iscsi_tgt/calsoft/calsoft.sh b/src/spdk/test/iscsi_tgt/calsoft/calsoft.sh
new file mode 100755
index 000000000..048b529d5
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/calsoft/calsoft.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+delete_tmp_conf_files() {
+ rm -f /usr/local/etc/its.conf
+}
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+
+rpc_py="$rootdir/scripts/rpc.py"
+calsoft_py="$testdir/calsoft.py"
+
+# Copy the calsoft config file to /usr/local/etc
+mkdir -p /usr/local/etc
+cp $testdir/its.conf /usr/local/etc/
+
+# Append target ip to calsoft config
+echo "IP=$TARGET_IP" >> /usr/local/etc/its.conf
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m 0x1 --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; delete_tmp_conf_files; exit 1 ' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py load_subsystem_config < $testdir/iscsi.json
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_auth_group 1 -c 'user:root secret:tester'
+$rpc_py iscsi_set_discovery_auth -g 1
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create -b MyBdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "MyBdev:0" ==> use MyBdev blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "0 0 0 1" ==> enable CHAP authentication using auth group 1
+$rpc_py iscsi_create_target_node Target3 Target3_alias 'MyBdev:0' $PORTAL_TAG:$INITIATOR_TAG 64 -g 1
+sleep 1
+
+if [ "$1" ]; then
+ $calsoft_py "$output_dir" "$1"
+ failed=$?
+else
+ $calsoft_py "$output_dir"
+ failed=$?
+fi
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $pid
+delete_tmp_conf_files
+exit $failed
diff --git a/src/spdk/test/iscsi_tgt/calsoft/iscsi.json b/src/spdk/test/iscsi_tgt/calsoft/iscsi.json
new file mode 100644
index 000000000..64b4a9595
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/calsoft/iscsi.json
@@ -0,0 +1,15 @@
+{
+ "subsystem": "iscsi",
+ "config": [
+ {
+ "params": {
+ "allow_duplicated_isid": true,
+ "nop_timeout": 30,
+ "nop_in_interval": 10,
+ "max_sessions": 256,
+ "error_recovery_level": 2
+ },
+ "method": "iscsi_set_options"
+ }
+ ]
+}
diff --git a/src/spdk/test/iscsi_tgt/calsoft/its.conf b/src/spdk/test/iscsi_tgt/calsoft/its.conf
new file mode 100644
index 000000000..6469dab63
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/calsoft/its.conf
@@ -0,0 +1,7 @@
+InitiatorName=iqn.1994-05.com.redhat:b3283535dc3b
+TargetName=iqn.2016-06.io.spdk:Target3
+DefaultTime2Retain=20
+DefaultTime2Wait=2
+AuthMethod=CHAP,None
+UserName=root
+PassWord=tester
diff --git a/src/spdk/test/iscsi_tgt/common.sh b/src/spdk/test/iscsi_tgt/common.sh
new file mode 100644
index 000000000..d42a2a3a2
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/common.sh
@@ -0,0 +1,209 @@
+# Network configuration
+TARGET_INTERFACE="spdk_tgt_int"
+INITIATOR_INTERFACE="spdk_init_int"
+TARGET_NAMESPACE="spdk_iscsi_ns"
+TARGET_NS_CMD=(ip netns exec "$TARGET_NAMESPACE")
+
+# iSCSI target configuration
+TARGET_IP=10.0.0.1
+INITIATOR_IP=10.0.0.2
+ISCSI_PORT=3260
+NETMASK=$INITIATOR_IP/32
+INITIATOR_TAG=2
+INITIATOR_NAME=ANY
+PORTAL_TAG=1
+ISCSI_APP=("${TARGET_NS_CMD[@]}" "${ISCSI_APP[@]}")
+if [ $SPDK_TEST_VPP -eq 1 ]; then
+ ISCSI_APP+=(-L sock_vpp)
+fi
+ISCSI_TEST_CORE_MASK=0xFF
+
+function create_veth_interfaces() {
+ # $1 = test type (posix/vpp)
+ ip netns del $TARGET_NAMESPACE || true
+ ip link delete $INITIATOR_INTERFACE || true
+
+ trap 'cleanup_veth_interfaces $1; exit 1' SIGINT SIGTERM EXIT
+
+ # Create veth (Virtual ethernet) interface pair
+ ip link add $INITIATOR_INTERFACE type veth peer name $TARGET_INTERFACE
+ ip addr add $INITIATOR_IP/24 dev $INITIATOR_INTERFACE
+ ip link set $INITIATOR_INTERFACE up
+
+ # Create and add interface for target to network namespace
+ ip netns add $TARGET_NAMESPACE
+ ip link set $TARGET_INTERFACE netns $TARGET_NAMESPACE
+
+ # Accept connections from veth interface
+ iptables -I INPUT 1 -i $INITIATOR_INTERFACE -p tcp --dport $ISCSI_PORT -j ACCEPT
+
+ "${TARGET_NS_CMD[@]}" ip link set $TARGET_INTERFACE up
+
+ if [ "$1" == "posix" ]; then
+ "${TARGET_NS_CMD[@]}" ip link set lo up
+ "${TARGET_NS_CMD[@]}" ip addr add $TARGET_IP/24 dev $TARGET_INTERFACE
+
+ # Verify connectivity
+ ping -c 1 $TARGET_IP
+ ip netns exec $TARGET_NAMESPACE ping -c 1 $INITIATOR_IP
+ else
+ start_vpp
+ fi
+}
+
+function cleanup_veth_interfaces() {
+ # $1 = test type (posix/vpp)
+ if [ "$1" == "vpp" ]; then
+ kill_vpp
+ fi
+
+ # Cleanup veth interfaces and network namespace
+ # Note: removing one veth, removes the pair
+ ip link delete $INITIATOR_INTERFACE
+ ip netns del $TARGET_NAMESPACE
+}
+
+function iscsitestinit() {
+ if [ "$1" == "iso" ]; then
+ $rootdir/scripts/setup.sh
+ if [ -n "$2" ]; then
+ create_veth_interfaces $2
+ else
+ # default to posix
+ create_veth_interfaces "posix"
+ fi
+ fi
+}
+
+function waitforiscsidevices() {
+ local num=$1
+
+ for ((i = 1; i <= 20; i++)); do
+ n=$(iscsiadm -m session -P 3 | grep -c "Attached scsi disk sd[a-z]*" || true)
+ if [ $n -ne $num ]; then
+ sleep 0.1
+ else
+ return 0
+ fi
+ done
+
+ return 1
+}
+
+function iscsitestfini() {
+ if [ "$1" == "iso" ]; then
+ if [ -n "$2" ]; then
+ cleanup_veth_interfaces $2
+ else
+ # default to posix
+ cleanup_veth_interfaces "posix"
+ fi
+ $rootdir/scripts/setup.sh reset
+ fi
+}
+
+function start_vpp() {
+ # We need to make sure that posix side doesn't send jumbo packets while
+ # for VPP side maximal size of MTU for TCP is 1460 and tests doesn't work
+ # stable with larger packets
+ MTU=1460
+ MTU_W_HEADER=$((MTU + 20))
+ ip link set dev $INITIATOR_INTERFACE mtu $MTU
+ ethtool -K $INITIATOR_INTERFACE tso off
+ ethtool -k $INITIATOR_INTERFACE
+
+ # Start VPP process in SPDK target network namespace
+ "${TARGET_NS_CMD[@]}" vpp \
+ unix { nodaemon cli-listen /run/vpp/cli.sock } \
+ dpdk { no-pci } \
+ session { evt_qs_memfd_seg } \
+ socksvr { socket-name /run/vpp-api.sock } \
+ plugins { \
+ plugin default { disable } \
+ plugin dpdk_plugin.so { enable } \
+ } &
+
+ vpp_pid=$!
+ echo "VPP Process pid: $vpp_pid"
+
+ gdb_attach $vpp_pid &
+
+ # Wait until VPP starts responding
+ xtrace_disable
+ counter=40
+ while [ $counter -gt 0 ]; do
+ vppctl show version | grep -E "vpp v[0-9]+\.[0-9]+" && break
+ counter=$((counter - 1))
+ sleep 0.5
+ done
+ xtrace_restore
+ if [ $counter -eq 0 ]; then
+ return 1
+ fi
+
+ # Below VPP commands are masked with "|| true" for the sake of
+ # running the test in the CI system. For reasons unknown when
+ # run via CI these commands result in 141 return code (pipefail)
+ # even despite producing valid output.
+ # Using "|| true" does not impact the "-e" flag used in test scripts
+ # because vppctl cli commands always return with 0, even if
+ # there was an error.
+ # As a result - grep checks on command outputs must be used to
+ # verify vpp configuration and connectivity.
+
+ # Setup host interface
+ vppctl create host-interface name $TARGET_INTERFACE || true
+ VPP_TGT_INT="host-$TARGET_INTERFACE"
+ vppctl set interface state $VPP_TGT_INT up || true
+ vppctl set interface ip address $VPP_TGT_INT $TARGET_IP/24 || true
+ vppctl set interface mtu $MTU $VPP_TGT_INT || true
+
+ vppctl show interface | tr -s " " | grep -E "host-$TARGET_INTERFACE [0-9]+ up $MTU/0/0/0"
+
+ # Disable session layer
+ # NOTE: VPP net framework should enable it itself.
+ vppctl session disable || true
+
+ # Verify connectivity
+ vppctl show int addr | grep -E "$TARGET_IP/24"
+ ip addr show $INITIATOR_INTERFACE
+ ip netns exec $TARGET_NAMESPACE ip addr show $TARGET_INTERFACE
+ sleep 3
+ # SC1010: ping -M do - in this case do is an option not bash special word
+ # shellcheck disable=SC1010
+ ping -c 1 $TARGET_IP -s $((MTU - 28)) -M do
+ vppctl ping $INITIATOR_IP repeat 1 size $((MTU - (28 + 8))) verbose | grep -E "$MTU_W_HEADER bytes from $INITIATOR_IP"
+}
+
+function kill_vpp() {
+ vppctl delete host-interface name $TARGET_INTERFACE || true
+
+ # Dump VPP configuration before kill
+ vppctl show api clients || true
+ vppctl show session || true
+ vppctl show errors || true
+
+ killprocess $vpp_pid
+}
+function initiator_json_config() {
+ # Prepare config file for iSCSI initiator
+ jq . <<- JSON
+ {
+ "subsystems": [
+ {
+ "subsystem": "bdev",
+ "config": [
+ {
+ "method": "bdev_iscsi_create",
+ "params": {
+ "name": "iSCSI0",
+ "url": "iscsi://$TARGET_IP/iqn.2016-06.io.spdk:disk1/0",
+ "initiator_iqn": "iqn.2016-06.io.spdk:disk1/0"
+ }
+ }${*:+,$*}
+ ]
+ }
+ ]
+ }
+ JSON
+}
diff --git a/src/spdk/test/iscsi_tgt/digests/digests.sh b/src/spdk/test/iscsi_tgt/digests/digests.sh
new file mode 100755
index 000000000..3a03c10ec
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/digests/digests.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+function node_login_fio_logout() {
+ for arg in "$@"; do
+ iscsiadm -m node -p $TARGET_IP:$ISCSI_PORT -o update -n node.conn[0].iscsi.$arg
+ done
+ iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+ waitforiscsidevices 1
+ $fio_py -p iscsi -i 512 -d 1 -t write -r 2
+ $fio_py -p iscsi -i 512 -d 1 -t read -r 2
+ iscsiadm -m node --logout -p $TARGET_IP:$ISCSI_PORT
+ waitforiscsidevices 0
+}
+
+function iscsi_header_digest_test() {
+ # Enable HeaderDigest to CRC32C
+ node_login_fio_logout "HeaderDigest -v CRC32C"
+
+ # Let iscsi target to decide its preference on
+ # HeaderDigest based on its capability.
+ node_login_fio_logout "HeaderDigest -v CRC32C,None"
+}
+
+function iscsi_header_data_digest_test() {
+ # Only enable HeaderDigest to CRC32C
+ node_login_fio_logout "HeaderDigest -v CRC32C" "DataDigest -v None"
+
+ # Only enable DataDigest to CRC32C
+ node_login_fio_logout "HeaderDigest -v None" "DataDigest -v CRC32C"
+
+ # Let iscsi target to decide its preference on both
+ # HeaderDigest and DataDigest based on its capability.
+ node_login_fio_logout "HeaderDigest -v CRC32C,None" "DataDigest -v CRC32C,None"
+
+ # Enable HeaderDigest and DataDigest both.
+ node_login_fio_logout "HeaderDigest -v CRC32C" "DataDigest -v CRC32C"
+}
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "Malloc0:0" ==> use Malloc0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target3 Target3_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+
+# iscsiadm installed by some Fedora releases loses the ability to set DataDigest parameter.
+# Check and avoid setting DataDigest.
+DataDigestAbility=$(iscsiadm -m node -p $TARGET_IP:$ISCSI_PORT -o update -n node.conn[0].iscsi.DataDigest -v None 2>&1 || true)
+if [ "$DataDigestAbility"x != x ]; then
+ run_test "iscsi_tgt_digest" iscsi_header_digest_test
+else
+ run_test "iscsi_tgt_data_digest" iscsi_header_data_digest_test
+fi
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+killprocess $pid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/ext4test/ext4test.sh b/src/spdk/test/iscsi_tgt/ext4test/ext4test.sh
new file mode 100755
index 000000000..8de417367
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/ext4test/ext4test.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+rpc_py="$rootdir/scripts/rpc.py"
+node_base="iqn.2013-06.com.intel.ch.spdk"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap '$rpc_py bdev_split_delete Name0n1 || true; killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 4 -b $node_base
+$rpc_py framework_start_init
+$rootdir/scripts/gen_nvme.sh --json | $rpc_py load_subsystem_config
+$rpc_py bdev_malloc_create 512 4096 --name Malloc0
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_error_create 'Malloc0'
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target0 Target0_alias EE_Malloc0:0 1:2 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 1
+
+trap 'for new_dir in $(dir -d /mnt/*dir); do umount $new_dir; rm -rf $new_dir; done;
+ iscsicleanup; killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+echo "Test error injection"
+$rpc_py bdev_error_inject_error EE_Malloc0 'all' 'failure' -n 1000
+
+dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+set +e
+waitforfile /dev/${dev}
+if make_filesystem ext4 /dev/${dev}; then
+ echo "mkfs successful - expected failure"
+ iscsicleanup
+ killprocess $pid
+ exit 1
+else
+ echo "mkfs failed as expected"
+fi
+set -e
+
+iscsicleanup
+$rpc_py bdev_error_inject_error EE_Malloc0 'clear' 'failure'
+$rpc_py iscsi_delete_target_node $node_base:Target0
+echo "Error injection test done"
+
+if [ -z "$NO_NVME" ]; then
+ bdev_size=$(get_bdev_size Nvme0n1)
+ split_size=$((bdev_size / 2))
+ if [ $split_size -gt 10000 ]; then
+ split_size=10000
+ fi
+ $rpc_py bdev_split_create Nvme0n1 2 -s $split_size
+ $rpc_py iscsi_create_target_node Target1 Target1_alias Nvme0n1p0:0 1:2 64 -d
+fi
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 1
+
+devs=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+for dev in $devs; do
+ make_filesystem ext4 /dev/${dev}
+ mkdir -p /mnt/${dev}dir
+ mount -o sync /dev/${dev} /mnt/${dev}dir
+
+ rsync -qav --exclude=".git" --exclude="*.o" $rootdir/ /mnt/${dev}dir/spdk
+
+ make -C /mnt/${dev}dir/spdk clean
+ (cd /mnt/${dev}dir/spdk && ./configure $(get_config_params))
+ make -C /mnt/${dev}dir/spdk -j16
+
+ # Print out space consumed on target device to help decide
+ # if/when we need to increase the size of the malloc LUN
+ df -h /dev/$dev
+
+ rm -rf /mnt/${dev}dir/spdk
+done
+
+for dev in $devs; do
+ umount /mnt/${dev}dir
+ rm -rf /mnt/${dev}dir
+
+ stats=($(cat /sys/block/$dev/stat))
+ echo ""
+ echo "$dev stats"
+ printf "READ IO cnt: % 8u merges: % 8u sectors: % 8u ticks: % 8u\n" \
+ ${stats[0]} ${stats[1]} ${stats[2]} ${stats[3]}
+ printf "WRITE IO cnt: % 8u merges: % 8u sectors: % 8u ticks: % 8u\n" \
+ ${stats[4]} ${stats[5]} ${stats[6]} ${stats[7]}
+ printf "in flight: % 8u io ticks: % 8u time in queue: % 8u\n" \
+ ${stats[8]} ${stats[9]} ${stats[10]}
+ echo ""
+done
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+$rpc_py bdev_split_delete Nvme0n1
+$rpc_py bdev_error_delete EE_Malloc0
+
+if [ -z "$NO_NVME" ]; then
+ $rpc_py bdev_nvme_detach_controller Nvme0
+fi
+
+killprocess $pid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/filesystem/filesystem.sh b/src/spdk/test/iscsi_tgt/filesystem/filesystem.sh
new file mode 100755
index 000000000..156b5bde3
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/filesystem/filesystem.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+source $rootdir/scripts/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+rpc_py="$rootdir/scripts/rpc.py"
+# Remove lvol bdevs and stores.
+function remove_backends() {
+ echo "INFO: Removing lvol bdev"
+ $rpc_py bdev_lvol_delete "lvs_0/lbd_0"
+
+ echo "INFO: Removing lvol stores"
+ $rpc_py bdev_lvol_delete_lvstore -l lvs_0
+
+ echo "INFO: Removing NVMe"
+ $rpc_py bdev_nvme_detach_controller Nvme0
+
+ return 0
+}
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+bdf=$(get_first_nvme_bdf)
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_nvme_attach_controller -b "Nvme0" -t "pcie" -a $bdf
+
+ls_guid=$($rpc_py bdev_lvol_create_lvstore Nvme0n1 lvs_0)
+free_mb=$(get_lvs_free_mb "$ls_guid")
+# Using maximum 2048MiB to reduce the test time
+if [ $free_mb -gt 2048 ]; then
+ $rpc_py bdev_lvol_create -u $ls_guid lbd_0 2048
+else
+ $rpc_py bdev_lvol_create -u $ls_guid lbd_0 $free_mb
+fi
+# "lvs_0/lbd_0:0" ==> use lvs_0/lbd_0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "256" ==> iSCSI queue depth 256
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target1 Target1_alias 'lvs_0/lbd_0:0' $PORTAL_TAG:$INITIATOR_TAG 256 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 1
+
+trap 'iscsicleanup; remove_backends; umount /mnt/device; rm -rf /mnt/device; killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+mkdir -p /mnt/device
+
+dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+waitforfile /dev/$dev
+parted -s /dev/$dev mklabel msdos
+parted -s /dev/$dev mkpart primary '0%' '100%'
+sleep 1
+
+function filesystem_test() {
+ fstype=$1
+
+ make_filesystem ${fstype} /dev/${dev}1
+ mount /dev/${dev}1 /mnt/device
+ if [ $RUN_NIGHTLY -eq 1 ]; then
+ fio -filename=/mnt/device/test -direct=1 -iodepth 64 -thread=1 -invalidate=1 -rw=randwrite -ioengine=libaio -bs=4k \
+ -size=1024M -name=job0
+ umount /mnt/device
+
+ iscsiadm -m node --logout
+ waitforiscsidevices 0
+ iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+ waitforiscsidevices 1
+
+ dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+ waitforfile /dev/${dev}1
+ mount -o rw /dev/${dev}1 /mnt/device
+ if [ -f "/mnt/device/test" ]; then
+ echo "File existed."
+ fio -filename=/mnt/device/test -direct=1 -iodepth 64 -thread=1 -invalidate=1 -rw=randread \
+ -ioengine=libaio -bs=4k -runtime=20 -time_based=1 -name=job0
+ else
+ echo "File doesn't exist."
+ exit 1
+ fi
+
+ rm -rf /mnt/device/test
+ umount /mnt/device
+ else
+ touch /mnt/device/aaa
+ umount /mnt/device
+
+ iscsiadm -m node --logout
+ waitforiscsidevices 0
+ iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+ waitforiscsidevices 1
+
+ dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+ waitforfile /dev/${dev}1
+ mount -o rw /dev/${dev}1 /mnt/device
+
+ if [ -f "/mnt/device/aaa" ]; then
+ echo "File existed."
+ else
+ echo "File doesn't exist."
+ exit 1
+ fi
+
+ rm -rf /mnt/device/aaa
+ umount /mnt/device
+ fi
+}
+
+run_test "iscsi_tgt_filesystem_ext4" filesystem_test "ext4"
+run_test "iscsi_tgt_filesystem_btrfs" filesystem_test "btrfs"
+run_test "iscsi_tgt_filesystem_xfs" filesystem_test "xfs"
+
+rm -rf /mnt/device
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+remove_backends
+killprocess $pid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/fio/fio.sh b/src/spdk/test/iscsi_tgt/fio/fio.sh
new file mode 100755
index 000000000..ae3a2f308
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/fio/fio.sh
@@ -0,0 +1,150 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+delete_tmp_files() {
+ rm -f $testdir/iscsi2.json
+ rm -f ./local-job0-0-verify.state
+ rm -f ./local-job1-1-verify.state
+}
+
+function running_config() {
+ # dump a config file from the running iscsi_tgt
+ $rpc_py save_config > $testdir/iscsi2.json
+ sleep 1
+
+ # now start iscsi_tgt again using the generated config file
+ # keep the same iscsiadm configuration to confirm that the
+ # config file matched the running configuration
+ killprocess $pid
+ trap 'iscsicleanup; delete_tmp_files; exit 1' SIGINT SIGTERM EXIT
+
+ timing_enter start_iscsi_tgt2
+
+ "${ISCSI_APP[@]}" --wait-for-rpc &
+ pid=$!
+ echo "Process pid: $pid"
+ trap 'iscsicleanup; killprocess $pid; delete_tmp_files; exit 1' SIGINT SIGTERM EXIT
+ waitforlisten $pid
+
+ $rpc_py load_config < $testdir/iscsi2.json
+
+ echo "iscsi_tgt is listening. Running tests..."
+
+ timing_exit start_iscsi_tgt2
+
+ sleep 1
+ $fio_py -p iscsi -i 4096 -d 1 -t randrw -r 5
+}
+
+if [ -z "$TARGET_IP" ]; then
+ echo "TARGET_IP not defined in environment"
+ exit 1
+fi
+
+if [ -z "$INITIATOR_IP" ]; then
+ echo "INITIATOR_IP not defined in environment"
+ exit 1
+fi
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=4096
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+
+$rpc_py load_config < $testdir/iscsi.json
+
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+# Create a RAID-0 bdev from two malloc bdevs
+malloc_bdevs="$($rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE) "
+malloc_bdevs+="$($rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)"
+$rpc_py bdev_raid_create -n raid0 -z 64 -r 0 -b "$malloc_bdevs"
+bdev=$($rpc_py bdev_malloc_create 1024 512)
+# "raid0:0" ==> use raid0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target3 Target3_alias "raid0:0 ${bdev}:1" $PORTAL_TAG:$INITIATOR_TAG 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 2
+
+trap 'iscsicleanup; killprocess $pid; iscsitestfini $1 $2; delete_tmp_files; exit 1' SIGINT SIGTERM EXIT
+
+$fio_py -p iscsi -i 4096 -d 1 -t randrw -r 1 -v
+$fio_py -p iscsi -i 131072 -d 32 -t randrw -r 1 -v
+$fio_py -p iscsi -i 524288 -d 128 -t randrw -r 1 -v
+$fio_py -p iscsi -i 1048576 -d 1024 -t read -r 1 -n 4
+
+if [ $RUN_NIGHTLY -eq 1 ]; then
+ $fio_py -p iscsi -i 4096 -d 1 -t write -r 300 -v
+
+ # Run the running_config test which will generate a config file from the
+ # running iSCSI target, then kill and restart the iSCSI target using the
+ # generated config file
+ # Temporarily disabled
+ # running_config
+fi
+
+# Start hotplug test case.
+$fio_py -p iscsi -i 1048576 -d 128 -t rw -r 10 &
+fio_pid=$!
+
+sleep 3
+
+# Delete raid0 blockdev
+$rpc_py bdev_raid_delete 'raid0'
+
+# Delete all allocated malloc blockdevs
+for malloc_bdev in $malloc_bdevs; do
+ $rpc_py bdev_malloc_delete $malloc_bdev
+done
+
+# Delete malloc device
+$rpc_py bdev_malloc_delete ${bdev}
+
+fio_status=0
+wait $fio_pid || fio_status=$?
+
+if [ $fio_status -eq 0 ]; then
+ echo "iscsi hotplug test: fio successful - expected failure"
+ exit 1
+else
+ echo "iscsi hotplug test: fio failed as expected"
+fi
+
+iscsicleanup
+$rpc_py iscsi_delete_target_node 'iqn.2016-06.io.spdk:Target3'
+
+delete_tmp_files
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $pid
+
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/fio/iscsi.json b/src/spdk/test/iscsi_tgt/fio/iscsi.json
new file mode 100644
index 000000000..d901fc78b
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/fio/iscsi.json
@@ -0,0 +1,32 @@
+{
+ "subsystems": [
+ {
+ "subsystem": "bdev",
+ "config": [
+ {
+ "params": {
+ "retry_count": 4,
+ "nvme_adminq_poll_period_us": 100000,
+ "nvme_ioq_poll_period_us": 0,
+ "action_on_timeout": "none"
+ },
+ "method": "bdev_nvme_set_options"
+ }
+ ]
+ },
+ {
+ "subsystem": "iscsi",
+ "config": [
+ {
+ "method": "iscsi_set_options",
+ "params": {
+ "nop_timeout": 30,
+ "node_base": "iqn.2016-06.io.spdk",
+ "max_sessions": 16,
+ "error_recovery_level": 0
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/spdk/test/iscsi_tgt/fuzz/fuzz.sh b/src/spdk/test/iscsi_tgt/fuzz/fuzz.sh
new file mode 100755
index 000000000..bc290fa8f
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/fuzz/fuzz.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+if [ -z "$TARGET_IP" ]; then
+ echo "TARGET_IP not defined in environment"
+ exit 1
+fi
+
+if [ -z "$INITIATOR_IP" ]; then
+ echo "INITIATOR_IP not defined in environment"
+ exit 1
+fi
+
+timing_enter iscsi_fuzz
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=4096
+
+rpc_py="$rootdir/scripts/rpc.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+iscsipid=$!
+echo "Process iscsipid: $iscsipid"
+
+trap 'killprocess $iscsipid; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $iscsipid
+# Fuzz initiator do not support nop-in yet. So we increase nop-in timeout value for now.
+$rpc_py iscsi_set_options -o 60 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+$rpc_py iscsi_create_target_node disk1 disk1_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 256 -d
+sleep 1
+
+trap 'killprocess $iscsipid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+$rootdir/test/app/fuzz/iscsi_fuzz/iscsi_fuzz -m 0xF0 -T $TARGET_IP -t 30 2> $output_dir/iscsi_autofuzz_logs.txt
+
+$rpc_py iscsi_delete_target_node 'iqn.2016-06.io.spdk:disk1'
+
+# Delete malloc device
+$rpc_py bdev_malloc_delete Malloc0
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $iscsipid
+
+iscsitestfini $1 $2
+
+timing_exit iscsi_fuzz
diff --git a/src/spdk/test/iscsi_tgt/initiator/initiator.sh b/src/spdk/test/iscsi_tgt/initiator/initiator.sh
new file mode 100755
index 000000000..5da1f320b
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/initiator/initiator.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+
+rpc_py="$rootdir/scripts/rpc.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m 0x2 -p 1 -s 512 --wait-for-rpc &
+pid=$!
+echo "iSCSI target launched. pid: $pid"
+trap 'killprocess $pid;exit 1' SIGINT SIGTERM EXIT
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 4
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "Malloc0:0" ==> use Malloc0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node disk1 disk1_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 256 -d
+sleep 1
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+"$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w verify -t 5 -s 512
+if [ $RUN_NIGHTLY -eq 1 ]; then
+ "$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w unmap -t 5 -s 512
+ "$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w flush -t 5 -s 512
+ "$rootdir/test/bdev/bdevperf/bdevperf" --json <(initiator_json_config) -q 128 -o 4096 -w reset -t 10 -s 512
+fi
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $pid
+
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/ip_migration/ip_migration.sh b/src/spdk/test/iscsi_tgt/ip_migration/ip_migration.sh
new file mode 100755
index 000000000..d737e01b3
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/ip_migration/ip_migration.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+# Namespaces are NOT used here on purpose. This test requires changes to detect
+# ifc_index for interface that was put into namespace. Needed for net_interface_add_ip_address.
+# Reset ISCSI_APP[] to use only the plain app for this test without TARGET_NS_CMD preset.
+source "$rootdir/test/common/applications.sh"
+NETMASK=127.0.0.0/24
+MIGRATION_ADDRESS=127.0.0.2
+
+function kill_all_iscsi_target() {
+ for ((i = 0; i < 2; i++)); do
+ rpc_addr="/var/tmp/spdk${i}.sock"
+ $rpc_py -s $rpc_addr spdk_kill_instance SIGTERM
+ done
+}
+
+function rpc_config() {
+ # $1 = RPC server address
+ # $2 = Netmask
+ $rpc_py -s $1 iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $2
+ $rpc_py -s $1 bdev_malloc_create 64 512
+}
+
+function rpc_validate_ip() {
+ # Always delete the IP first in case it is there already
+ cmd="$rpc_py -s $1 net_interface_delete_ip_address 1 $MIGRATION_ADDRESS"
+ if $cmd; then
+ echo "Delete existing IP succeeded."
+ else
+ echo "Ignore the failure as IP did not exist."
+ fi
+
+ cmd="$rpc_py -s $1 net_interface_add_ip_address 1 $MIGRATION_ADDRESS"
+ if $cmd; then
+ echo "Add new IP succeeded."
+ else
+ echo "Add new IP failed. Expected to succeed..."
+ exit 1
+ fi
+ # Add same IP again
+ if $cmd; then
+ echo "Same IP existed. Expected to fail..."
+ exit 1
+ fi
+
+ cmd="$rpc_py -s $1 net_interface_delete_ip_address 1 $MIGRATION_ADDRESS"
+ if $cmd; then
+ echo "Delete existing IP succeeded."
+ else
+ echo "Delete existing IP failed. Expected to succeed..."
+ exit 1
+ fi
+ # Delete same IP again
+ if $cmd; then
+ echo "No required IP existed. Expected to fail..."
+ exit 1
+ fi
+}
+
+function rpc_add_target_node() {
+ $rpc_py -s $1 net_interface_add_ip_address 1 $MIGRATION_ADDRESS
+ $rpc_py -s $1 iscsi_create_portal_group $PORTAL_TAG $MIGRATION_ADDRESS:$ISCSI_PORT
+ $rpc_py -s $1 iscsi_create_target_node target1 target1_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+ $rpc_py -s $1 net_interface_delete_ip_address 1 $MIGRATION_ADDRESS
+}
+
+echo "Running ip migration tests"
+for ((i = 0; i < 2; i++)); do
+ timing_enter start_iscsi_tgt_$i
+
+ rpc_addr="/var/tmp/spdk${i}.sock"
+
+ # TODO: run the different iSCSI instances on non-overlapping CPU masks
+ "${ISCSI_APP[@]}" -r $rpc_addr -i $i -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+ pid=$!
+ echo "Process pid: $pid"
+
+ trap 'kill_all_iscsi_target; exit 1' SIGINT SIGTERM EXIT
+
+ waitforlisten $pid $rpc_addr
+ $rpc_py -s $rpc_addr iscsi_set_options -o 30 -a 64
+ $rpc_py -s $rpc_addr framework_start_init
+ echo "iscsi_tgt is listening. Running tests..."
+
+ timing_exit start_iscsi_tgt_$i
+
+ rpc_config $rpc_addr $NETMASK
+ trap 'kill_all_iscsi_target; iscsitestfini $1 $2; exit 1' \
+ SIGINT SIGTERM EXIT
+done
+
+rpc_first_addr="/var/tmp/spdk0.sock"
+rpc_validate_ip $rpc_first_addr
+rpc_add_target_node $rpc_first_addr
+
+sleep 1
+iscsiadm -m discovery -t sendtargets -p $MIGRATION_ADDRESS:$ISCSI_PORT
+sleep 1
+iscsiadm -m node --login -p $MIGRATION_ADDRESS:$ISCSI_PORT
+waitforiscsidevices 1
+
+# fio tests for multi-process
+$fio_py -p iscsi -i 4096 -d 32 -t randrw -r 12 &
+fiopid=$!
+sleep 3
+
+$rpc_py -s $rpc_first_addr spdk_kill_instance SIGTERM
+
+rpc_second_addr="/var/tmp/spdk1.sock"
+rpc_add_target_node $rpc_second_addr
+
+wait $fiopid
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+
+$rpc_py -s $rpc_second_addr spdk_kill_instance SIGTERM
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/iscsi_tgt.sh b/src/spdk/test/iscsi_tgt/iscsi_tgt.sh
new file mode 100755
index 000000000..0316229b6
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/iscsi_tgt.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../..)
+source $rootdir/test/common/autotest_common.sh
+
+if [ ! $(uname -s) = Linux ]; then
+ exit 0
+fi
+
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = test type (posix/vpp)
+if [ "$1" == "posix" ] || [ "$1" == "vpp" ]; then
+ TEST_TYPE=$1
+else
+ echo "No iSCSI test type specified"
+ exit 1
+fi
+
+# Run cleanup once to make sure we remove any stale iscsiadm
+# entries if they were missed in previous runs
+iscsicleanup
+
+# Network configuration
+create_veth_interfaces $TEST_TYPE
+
+trap 'cleanup_veth_interfaces $TEST_TYPE; exit 1' SIGINT SIGTERM EXIT
+
+run_test "iscsi_tgt_sock" ./test/iscsi_tgt/sock/sock.sh $TEST_TYPE
+if [ "$TEST_TYPE" == "posix" ]; then
+ # calsoft doesn't handle TCP stream properly and fails decoding iSCSI
+ # requests when are divided by TCP segmentation. This is very common
+ # situation for VPP and causes that calsoft.sh never PASS.
+ if [[ -d /usr/local/calsoft ]]; then
+ run_test "iscsi_tgt_calsoft" ./test/iscsi_tgt/calsoft/calsoft.sh
+ else
+ skip_run_test_with_warning "WARNING: Calsoft binaries not found, skipping test!"
+ fi
+fi
+run_test "iscsi_tgt_filesystem" ./test/iscsi_tgt/filesystem/filesystem.sh
+run_test "iscsi_tgt_reset" ./test/iscsi_tgt/reset/reset.sh
+run_test "iscsi_tgt_rpc_config" ./test/iscsi_tgt/rpc_config/rpc_config.sh $TEST_TYPE
+run_test "iscsi_tgt_iscsi_lvol" ./test/iscsi_tgt/lvol/iscsi_lvol.sh
+run_test "iscsi_tgt_fio" ./test/iscsi_tgt/fio/fio.sh
+run_test "iscsi_tgt_qos" ./test/iscsi_tgt/qos/qos.sh
+
+# IP Migration tests do not support network namespaces,
+# they can only be run on posix sockets.
+if [ "$TEST_TYPE" == "posix" ]; then
+ run_test "iscsi_tgt_ip_migration" ./test/iscsi_tgt/ip_migration/ip_migration.sh
+fi
+run_test "iscsi_tgt_trace_record" ./test/iscsi_tgt/trace_record/trace_record.sh
+
+if [ $RUN_NIGHTLY -eq 1 ]; then
+ if [ $SPDK_TEST_PMDK -eq 1 ]; then
+ run_test "iscsi_tgt_pmem" ./test/iscsi_tgt/pmem/iscsi_pmem.sh 4096 10
+ fi
+ run_test "iscsi_tgt_ext4test" ./test/iscsi_tgt/ext4test/ext4test.sh
+ run_test "iscsi_tgt_digests" ./test/iscsi_tgt/digests/digests.sh
+fi
+if [ $SPDK_TEST_RBD -eq 1 ]; then
+ # RBD tests do not support network namespaces,
+ # they can only be run on posix sockets.
+ if [ "$TEST_TYPE" == "posix" ]; then
+ if ! hash ceph; then
+ echo "ERROR: SPDK_TEST_RBD requested but no ceph installed!"
+ false
+ fi
+ run_test "iscsi_tgt_rbd" ./test/iscsi_tgt/rbd/rbd.sh
+ fi
+fi
+
+trap 'cleanup_veth_interfaces $TEST_TYPE; exit 1' SIGINT SIGTERM EXIT
+
+if [ $SPDK_TEST_NVMF -eq 1 ]; then
+ # NVMe-oF tests do not support network namespaces,
+ # they can only be run on posix sockets.
+ if [ "$TEST_TYPE" == "posix" ]; then
+ # Test configure remote NVMe device from rpc and conf file
+ run_test "iscsi_tgt_fio_remote_nvme" ./test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh
+ fi
+fi
+
+if [ $RUN_NIGHTLY -eq 1 ]; then
+ if [ "$TEST_TYPE" == "posix" ]; then
+ run_test "iscsi_tgt_fuzz" ./test/iscsi_tgt/fuzz/fuzz.sh
+ fi
+ run_test "iscsi_tgt_multiconnection" ./test/iscsi_tgt/multiconnection/multiconnection.sh
+fi
+
+if [ $SPDK_TEST_ISCSI_INITIATOR -eq 1 ]; then
+ run_test "iscsi_tgt_initiator" ./test/iscsi_tgt/initiator/initiator.sh
+ run_test "iscsi_tgt_bdev_io_wait" ./test/iscsi_tgt/bdev_io_wait/bdev_io_wait.sh
+fi
+
+cleanup_veth_interfaces $TEST_TYPE
+trap - SIGINT SIGTERM EXIT
diff --git a/src/spdk/test/iscsi_tgt/lvol/iscsi_lvol.sh b/src/spdk/test/iscsi_tgt/lvol/iscsi_lvol.sh
new file mode 100755
index 000000000..e55899d56
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/lvol/iscsi_lvol.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+MALLOC_BDEV_SIZE=128
+MALLOC_BLOCK_SIZE=512
+if [ $RUN_NIGHTLY -eq 1 ]; then
+ NUM_LVS=10
+ NUM_LVOL=10
+else
+ NUM_LVS=2
+ NUM_LVOL=2
+fi
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'iscsicleanup; killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+timing_enter setup
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+# Create the first LVS from a Raid-0 bdev, which is created from two malloc bdevs
+# Create remaining LVSs from a malloc bdev, respectively
+for i in $(seq 1 $NUM_LVS); do
+ INITIATOR_TAG=$((i + 2))
+ $rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+ if [ $i -eq 1 ]; then
+ # construct RAID bdev and put its name in $bdev
+ malloc_bdevs="$($rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE) "
+ malloc_bdevs+="$($rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)"
+ $rpc_py bdev_raid_create -n raid0 -z 64 -r 0 -b "$malloc_bdevs"
+ bdev="raid0"
+ else
+ # construct malloc bdev and put its name in $bdev
+ bdev=$($rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)
+ fi
+ ls_guid=$($rpc_py bdev_lvol_create_lvstore $bdev lvs_$i -c 1048576)
+ LUNs=""
+ for j in $(seq 1 $NUM_LVOL); do
+ lb_name=$($rpc_py bdev_lvol_create -u $ls_guid lbd_$j 10)
+ LUNs+="$lb_name:$((j - 1)) "
+ done
+ $rpc_py iscsi_create_target_node Target$i Target${i}_alias "$LUNs" "1:$INITIATOR_TAG" 256 -d
+done
+timing_exit setup
+
+sleep 1
+
+timing_enter discovery
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices $((NUM_LVS * NUM_LVOL))
+timing_exit discovery
+
+timing_enter fio
+$fio_py -p iscsi -i 131072 -d 8 -t randwrite -r 10 -v
+timing_exit fio
+
+rm -f ./local-job0-0-verify.state
+trap - SIGINT SIGTERM EXIT
+
+rm -f ./local-job*
+iscsicleanup
+killprocess $pid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/multiconnection/multiconnection.sh b/src/spdk/test/iscsi_tgt/multiconnection/multiconnection.sh
new file mode 100755
index 000000000..badf70197
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/multiconnection/multiconnection.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+CONNECTION_NUMBER=30
+
+# Remove lvol bdevs and stores.
+function remove_backends() {
+ echo "INFO: Removing lvol bdevs"
+ for i in $(seq 1 $CONNECTION_NUMBER); do
+ lun="lvs0/lbd_$i"
+ $rpc_py bdev_lvol_delete $lun
+ echo -e "\tINFO: lvol bdev $lun removed"
+ done
+ sleep 1
+
+ echo "INFO: Removing lvol stores"
+ $rpc_py bdev_lvol_delete_lvstore -l lvs0
+ echo "INFO: lvol store lvs0 removed"
+
+ echo "INFO: Removing NVMe"
+ $rpc_py bdev_nvme_detach_controller Nvme0
+
+ return 0
+}
+
+timing_enter start_iscsi_tgt
+"${ISCSI_APP[@]}" --wait-for-rpc &
+iscsipid=$!
+echo "iSCSI target launched. pid: $iscsipid"
+trap 'remove_backends; iscsicleanup; killprocess $iscsipid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $iscsipid
+$rpc_py iscsi_set_options -o 30 -a 128
+$rpc_py framework_start_init
+$rootdir/scripts/gen_nvme.sh --json | $rpc_py load_subsystem_config
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+
+echo "Creating an iSCSI target node."
+ls_guid=$($rpc_py bdev_lvol_create_lvstore "Nvme0n1" "lvs0" -c 1048576)
+
+# Assign even size for each lvol_bdev.
+get_lvs_free_mb $ls_guid
+lvol_bdev_size=$((free_mb / CONNECTION_NUMBER))
+for i in $(seq 1 $CONNECTION_NUMBER); do
+ $rpc_py bdev_lvol_create -u $ls_guid lbd_$i $lvol_bdev_size
+done
+
+for i in $(seq 1 $CONNECTION_NUMBER); do
+ lun="lvs0/lbd_$i:0"
+ $rpc_py iscsi_create_target_node Target$i Target${i}_alias "$lun" $PORTAL_TAG:$INITIATOR_TAG 256 -d
+done
+sleep 1
+
+echo "Logging into iSCSI target."
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices $CONNECTION_NUMBER
+
+echo "Running FIO"
+$fio_py -p iscsi -i 131072 -d 64 -t randrw -r 5
+$fio_py -p iscsi -i 262144 -d 16 -t randwrite -r 10
+sync
+
+trap - SIGINT SIGTERM EXIT
+
+rm -f ./local-job*
+iscsicleanup
+remove_backends
+killprocess $iscsipid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh b/src/spdk/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh
new file mode 100755
index 000000000..38329dc43
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/nvmf/common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+nvmftestinit
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+# Namespaces are NOT used here on purpose. Rxe_cfg utilility used for NVMf tests do not support namespaces.
+TARGET_IP=127.0.0.1
+INITIATOR_IP=127.0.0.1
+NETMASK=$INITIATOR_IP/32
+
+function run_nvme_remote() {
+ echo "now use $1 method to run iscsi tgt."
+
+ iscsi_rpc_addr="/var/tmp/spdk-iscsi.sock"
+ "${ISCSI_APP[@]}" -r "$iscsi_rpc_addr" -m 0x1 -p 0 -s 512 --wait-for-rpc &
+ iscsipid=$!
+ echo "iSCSI target launched. pid: $iscsipid"
+ trap 'killprocess $iscsipid; iscsitestfini $1 $2; nvmftestfini; exit 1' SIGINT SIGTERM EXIT
+ waitforlisten $iscsipid "$iscsi_rpc_addr"
+ $rpc_py -s "$iscsi_rpc_addr" iscsi_set_options -o 30 -a 16
+ $rpc_py -s "$iscsi_rpc_addr" framework_start_init
+ if [ "$1" = "remote" ]; then
+ $rpc_py -s $iscsi_rpc_addr bdev_nvme_attach_controller -b "Nvme0" -t "rdma" -f "ipv4" -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT -n nqn.2016-06.io.spdk:cnode1
+ fi
+
+ echo "iSCSI target has started."
+
+ timing_exit start_iscsi_tgt
+
+ echo "Creating an iSCSI target node."
+ $rpc_py -s "$iscsi_rpc_addr" iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+ $rpc_py -s "$iscsi_rpc_addr" iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+ if [ "$1" = "local" ]; then
+ $rpc_py -s "$iscsi_rpc_addr" bdev_nvme_attach_controller -b "Nvme0" -t "rdma" -f "ipv4" -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT -n nqn.2016-06.io.spdk:cnode1
+ fi
+ $rpc_py -s "$iscsi_rpc_addr" iscsi_create_target_node Target1 Target1_alias 'Nvme0n1:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+ sleep 1
+
+ echo "Logging in to iSCSI target."
+ iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+ iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+}
+
+# Start the NVMf target
+"${NVMF_APP[@]}" -m 0x2 -p 1 -s 512 --wait-for-rpc &
+nvmfpid=$!
+echo "NVMf target launched. pid: $nvmfpid"
+trap 'iscsitestfini $1 $2; nvmftestfini; exit 1' SIGINT SIGTERM EXIT
+waitforlisten $nvmfpid
+$rpc_py framework_start_init
+$rpc_py nvmf_create_transport -t RDMA -u 8192
+echo "NVMf target has started."
+bdevs=$($rpc_py bdev_malloc_create 64 512)
+$rpc_py nvmf_create_subsystem nqn.2016-06.io.spdk:cnode1 -a -s SPDK00000000000001
+$rpc_py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode1 -t rdma -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT
+for bdev in $bdevs; do
+ $rpc_py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 $bdev
+done
+echo "NVMf subsystem created."
+
+timing_enter start_iscsi_tgt
+
+run_nvme_remote "local"
+
+trap 'iscsicleanup; killprocess $iscsipid;
+ rm -f ./local-job0-0-verify.state; iscsitestfini $1 $2; nvmftestfini; exit 1' SIGINT SIGTERM EXIT
+
+echo "Running FIO"
+$fio_py -p iscsi -i 4096 -d 1 -t randrw -r 1 -v
+
+rm -f ./local-job0-0-verify.state
+iscsicleanup
+killprocess $iscsipid
+
+run_nvme_remote "remote"
+
+echo "Running FIO"
+$fio_py -p iscsi -i 4096 -d 1 -t randrw -r 1 -v
+
+rm -f ./local-job0-0-verify.state
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+killprocess $iscsipid
+$rpc_py nvmf_delete_subsystem nqn.2016-06.io.spdk:cnode1
+
+iscsitestfini $1 $2
+nvmftestfini
diff --git a/src/spdk/test/iscsi_tgt/perf/iscsi_initiator.sh b/src/spdk/test/iscsi_tgt/perf/iscsi_initiator.sh
new file mode 100755
index 000000000..b7d08bbc2
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/perf/iscsi_initiator.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+testdir=$(readlink -f $(dirname $0))
+ISCSI_PORT=3260
+FIO_PATH=$1
+IP_T=$2
+
+set -xe
+trap "exit 1" ERR SIGTERM SIGABRT
+
+if [ ! -x $FIO_PATH/fio ]; then
+ error "Invalid path of fio binary"
+fi
+
+function run_spdk_iscsi_fio() {
+ $FIO_PATH/fio $testdir/perf.job "$@" --output-format=json
+}
+
+mkdir -p $testdir/perf_output
+iscsi_fio_results="$testdir/perf_output/iscsi_fio.json"
+trap "iscsiadm -m node --logout; iscsiadm -m node -o delete; exit 1" ERR SIGTERM SIGABRT
+iscsiadm -m discovery -t sendtargets -p $IP_T:$ISCSI_PORT
+iscsiadm -m node --login -p $IP_T:$ISCSI_PORT
+waitforiscsidevices 1
+
+disks=($(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}'))
+for ((i = 0; i < ${#disks[@]}; i++)); do
+ filename+=$(printf /dev/%s: "${disks[i]}")
+ waitforfile $filename
+ echo noop > /sys/block/${disks[i]}/queue/scheduler
+ echo "2" > /sys/block/${disks[i]}/queue/nomerges
+ echo "1024" > /sys/block/${disks[i]}/queue/nr_requests
+done
+
+run_spdk_iscsi_fio --filename=$filename "--output=$iscsi_fio_results"
+
+iscsiadm -m node --logout || true
+iscsiadm -m node -o delete || true
diff --git a/src/spdk/test/iscsi_tgt/perf/iscsi_target.sh b/src/spdk/test/iscsi_tgt/perf/iscsi_target.sh
new file mode 100755
index 000000000..ec02f9e0c
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/perf/iscsi_target.sh
@@ -0,0 +1,134 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+rpc_py="$rootdir/scripts/rpc.py -s $testdir/rpc_iscsi.sock"
+
+BLK_SIZE=4096
+RW=randrw
+MIX=100
+IODEPTH=128
+RUNTIME=60
+RAMP_TIME=10
+FIO_PATH=$CONFIG_FIO_SOURCE_DIR
+DISKNO="ALL"
+CPUMASK=0x02
+NUM_JOBS=1
+ISCSI_TGT_CM=0x02
+
+# Performance test for iscsi_tgt, run on devices with proper hardware support (target and inititator)
+function usage() {
+ [[ -n $2 ]] && (
+ echo "$2"
+ echo ""
+ )
+ echo "Usage: $(basename $1) [options]"
+ echo "-h, --help Print help and exit"
+ echo " --fiopath=PATH Path to fio directory on initiator. [default=$FIO_PATH]"
+ echo " --disk_no=INT,ALL Number of disks to test on, if =ALL then test on all found disks. [default=$DISKNO]"
+ echo " --target_ip=IP The IP address of target used for test."
+ echo " --initiator_ip=IP The IP address of initiator used for test."
+ echo " --init_mgmnt_ip=IP The IP address of initiator used for communication."
+ echo " --iscsi_tgt_mask=HEX iscsi_tgt core mask. [default=$ISCSI_TGT_CM]"
+}
+
+while getopts 'h-:' optchar; do
+ case "$optchar" in
+ -)
+ case "$OPTARG" in
+ help)
+ usage $0
+ exit 0
+ ;;
+ fiopath=*) FIO_BIN="${OPTARG#*=}" ;;
+ disk_no=*) DISKNO="${OPTARG#*=}" ;;
+ target_ip=*) TARGET_IP="${OPTARG#*=}" ;;
+ initiator_ip=*) INITIATOR_IP="${OPTARG#*=}" ;;
+ init_mgmnt_ip=*) IP_I_SSH="${OPTARG#*=}" ;;
+ iscsi_tgt_mask=*) ISCSI_TGT_CM="${OPTARG#*=}" ;;
+ *)
+ usage $0 echo "Invalid argument '$OPTARG'"
+ exit 1
+ ;;
+ esac
+ ;;
+ h)
+ usage $0
+ exit 0
+ ;;
+ *)
+ usage $0 "Invalid argument '$optchar'"
+ exit 1
+ ;;
+ esac
+done
+
+if [ -z "$TARGET_IP" ]; then
+ error "No IP address of iscsi target is given"
+fi
+
+if [ -z "$INITIATOR_IP" ]; then
+ error "No IP address of iscsi initiator is given"
+fi
+
+if [ -z "$IP_I_SSH" ]; then
+ error "No IP address of initiator is given"
+fi
+
+if [ $EUID -ne 0 ]; then
+ error "INFO: This script must be run with root privileges"
+fi
+
+function ssh_initiator() {
+ # shellcheck disable=SC2029
+ # (we want to expand $@ immediately, not on the VM)
+ ssh -i $HOME/.ssh/spdk_vhost_id_rsa root@$IP_I_SSH "$@"
+}
+
+NETMASK=$INITIATOR_IP/32
+iscsi_fio_results="$testdir/perf_output/iscsi_fio.json"
+rm -rf $iscsi_fio_results
+mkdir -p $testdir/perf_output
+touch $iscsi_fio_results
+
+timing_enter run_iscsi_app
+$SPDK_BIN_DIR/iscsi_tgt -m $ISCSI_TGT_CM -r $testdir/rpc_iscsi.sock --wait-for-rpc &
+pid=$!
+trap 'rm -f $testdir/perf.job; killprocess $pid; print_backtrace; exit 1' ERR SIGTERM SIGABRT
+waitforlisten "$pid" "$testdir/rpc_iscsi.sock"
+$rpc_py iscsi_set_options -b "iqn.2016-06.io.spdk" -f "/usr/local/etc/spdk/auth.conf" -o 30 -i -l 0 -a 16
+$rpc_py framework_start_init
+$rootdir/scripts/gen_nvme.sh --json | $rpc_py load_subsystem_config
+sleep 1
+timing_exit run_iscsi_app
+
+timing_enter iscsi_config
+bdevs=($($rpc_py bdev_get_bdevs | jq -r '.[].name'))
+if [[ $DISKNO == "ALL" ]] || [[ $DISKNO == "all" ]]; then
+ DISKNO=${#bdevs[@]}
+elif [[ $DISKNO -gt ${#bdevs[@]} ]] || [[ ! $DISKNO =~ ^[0-9]+$ ]]; then
+ error "Required device number ($DISKNO) is not a valid number or it's larger than the number of devices found (${#bdevs[@]})"
+fi
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+
+for ((i = 0; i < DISKNO; i++)); do
+ $rpc_py iscsi_create_target_node Target${i} Target${i}_alias "${bdevs[i]}:0" "$PORTAL_TAG:$INITIATOR_TAG" 64 -d
+done
+
+ssh_initiator "cat > perf.job" < $testdir/perf.job
+rm -f $testdir/perf.job
+timing_exit iscsi_config
+
+timing_enter iscsi_initiator
+ssh_initiator bash -s - $FIO_PATH $TARGET_IP < $testdir/iscsi_initiator.sh
+timing_exit iscsi_initiator
+
+ssh_initiator "cat perf_output/iscsi_fio.json" > $iscsi_fio_results
+ssh_initiator "rm -rf perf_output perf.job"
+
+killprocess $pid
diff --git a/src/spdk/test/iscsi_tgt/perf/perf.job b/src/spdk/test/iscsi_tgt/perf/perf.job
new file mode 100644
index 000000000..0f169d4ab
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/perf/perf.job
@@ -0,0 +1,19 @@
+[global]
+thread=1
+group_reporting=1
+direct=1
+norandommap=1
+ioengine=libaio
+percentile_list=50:90:99:99.5:99.9:99.99:99.999
+
+[4k_rand_read_qd_128]
+stonewall
+time_based=1
+runtime=60
+ramp_time=10
+bs=4096
+rw=randrw
+rwmixread=100
+iodepth=128
+cpumask=0x02
+numjobs=1
diff --git a/src/spdk/test/iscsi_tgt/pmem/iscsi_pmem.sh b/src/spdk/test/iscsi_tgt/pmem/iscsi_pmem.sh
new file mode 100755
index 000000000..da6fd77f4
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/pmem/iscsi_pmem.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+BLOCKSIZE=$1
+RUNTIME=$2
+PMEM_BDEVS=""
+PMEM_SIZE=128
+PMEM_BLOCK_SIZE=512
+TGT_NR=10
+PMEM_PER_TGT=1
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_target
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'iscsicleanup; killprocess $pid; rm -f /tmp/pool_file*; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+timing_exit start_iscsi_target
+
+timing_enter setup
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+for i in $(seq 1 $TGT_NR); do
+ INITIATOR_TAG=$((i + 1))
+ $rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+
+ luns=""
+ for j in $(seq 1 $PMEM_PER_TGT); do
+ $rpc_py create_pmem_pool /tmp/pool_file${i}_${j} $PMEM_SIZE $PMEM_BLOCK_SIZE
+ bdevs_name="$($rpc_py bdev_pmem_create -n pmem${i}_${j} /tmp/pool_file${i}_${j})"
+ PMEM_BDEVS+="$bdevs_name "
+ luns+="$bdevs_name:$((j - 1)) "
+ done
+ $rpc_py iscsi_create_target_node Target$i Target${i}_alias "$luns" "1:$INITIATOR_TAG " 256 -d
+done
+timing_exit setup
+sleep 1
+
+timing_enter discovery
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+timing_exit discovery
+
+timing_enter fio_test
+$fio_py -p iscsi -i $BLOCKSIZE -d 64 -t randwrite -r $RUNTIME -v
+timing_exit fio_test
+
+iscsicleanup
+
+for pmem in $PMEM_BDEVS; do
+ $rpc_py bdev_pmem_delete $pmem
+done
+
+for i in $(seq 1 $TGT_NR); do
+ for c in $(seq 1 $PMEM_PER_TGT); do
+ $rpc_py bdev_pmem_delete_pool /tmp/pool_file${i}_${c}
+ done
+done
+
+trap - SIGINT SIGTERM EXIT
+
+rm -f ./local-job*
+rm -f /tmp/pool_file*
+killprocess $pid
diff --git a/src/spdk/test/iscsi_tgt/qos/qos.sh b/src/spdk/test/iscsi_tgt/qos/qos.sh
new file mode 100755
index 000000000..0a8015e18
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/qos/qos.sh
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+function run_fio() {
+ local bdev_name=$1
+ local iostats
+ local start_io_count
+ local start_bytes_read
+ local end_io_count
+ local end_bytes_read
+ local run_time=5
+
+ iostats=$($rpc_py bdev_get_iostat -b $bdev_name)
+ start_io_count=$(jq -r '.bdevs[0].num_read_ops' <<< "$iostats")
+ start_bytes_read=$(jq -r '.bdevs[0].bytes_read' <<< "$iostats")
+
+ $fio_py -p iscsi -i 1024 -d 128 -t randread -r $run_time
+
+ iostats=$($rpc_py bdev_get_iostat -b $bdev_name)
+ end_io_count=$(jq -r '.bdevs[0].num_read_ops' <<< "$iostats")
+ end_bytes_read=$(jq -r '.bdevs[0].bytes_read' <<< "$iostats")
+
+ IOPS_RESULT=$(((end_io_count - start_io_count) / run_time))
+ BANDWIDTH_RESULT=$(((end_bytes_read - start_bytes_read) / run_time))
+}
+
+function verify_qos_limits() {
+ local result=$1
+ local limit=$2
+
+ [ "$(bc <<< "$result > $limit*0.85")" -eq 1 ] \
+ && [ "$(bc <<< "$result < $limit*1.05")" -eq 1 ]
+}
+
+if [ -z "$TARGET_IP" ]; then
+ echo "TARGET_IP not defined in environment"
+ exit 1
+fi
+
+if [ -z "$INITIATOR_IP" ]; then
+ echo "INITIATOR_IP not defined in environment"
+ exit 1
+fi
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+IOPS_RESULT=
+BANDWIDTH_RESULT=
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" &
+pid=$!
+echo "Process pid: $pid"
+trap 'killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+waitforlisten $pid
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "Malloc0:0" ==> use Malloc0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target1 Target1_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+
+trap 'iscsicleanup; killprocess $pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+# Run FIO without any QOS limits to determine the raw performance
+run_fio Malloc0
+
+# Set IOPS/bandwidth limit to 50% of the actual unrestrained performance.
+IOPS_LIMIT=$((IOPS_RESULT / 2))
+BANDWIDTH_LIMIT=$((BANDWIDTH_RESULT / 2))
+# Set READ bandwidth limit to 50% of the RW bandwidth limit to be able
+# to differentiate those two.
+READ_BANDWIDTH_LIMIT=$((BANDWIDTH_LIMIT / 2))
+
+# Also round them down to nearest multiple of either 1000 IOPS or 1MB BW
+# which are the minimal QoS granularities
+IOPS_LIMIT=$((IOPS_LIMIT / 1000 * 1000))
+BANDWIDTH_LIMIT_MB=$((BANDWIDTH_LIMIT / 1024 / 1024))
+BANDWIDTH_LIMIT=$((BANDWIDTH_LIMIT_MB * 1024 * 1024))
+READ_BANDWIDTH_LIMIT_MB=$((READ_BANDWIDTH_LIMIT / 1024 / 1024))
+READ_BANDWIDTH_LIMIT=$((READ_BANDWIDTH_LIMIT_MB * 1024 * 1024))
+
+# Limit the I/O rate by RPC, then confirm the observed rate matches.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_ios_per_sec $IOPS_LIMIT
+run_fio Malloc0
+verify_qos_limits $IOPS_RESULT $IOPS_LIMIT
+
+# Now disable the rate limiting, and confirm the observed rate is not limited anymore.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_ios_per_sec 0
+run_fio Malloc0
+[ "$IOPS_RESULT" -gt "$IOPS_LIMIT" ]
+
+# Limit the I/O rate again.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_ios_per_sec $IOPS_LIMIT
+run_fio Malloc0
+verify_qos_limits $IOPS_RESULT $IOPS_LIMIT
+
+echo "I/O rate limiting tests successful"
+
+# Limit the I/O bandwidth rate by RPC, then confirm the observed rate matches.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_ios_per_sec 0 --rw_mbytes_per_sec $BANDWIDTH_LIMIT_MB
+run_fio Malloc0
+verify_qos_limits $BANDWIDTH_RESULT $BANDWIDTH_LIMIT
+
+# Now disable the bandwidth rate limiting, and confirm the observed rate is not limited anymore.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_mbytes_per_sec 0
+run_fio Malloc0
+[ "$BANDWIDTH_RESULT" -gt "$BANDWIDTH_LIMIT" ]
+
+# Limit the I/O bandwidth rate again with both read/write and read/only.
+$rpc_py bdev_set_qos_limit Malloc0 --rw_mbytes_per_sec $BANDWIDTH_LIMIT_MB --r_mbytes_per_sec $READ_BANDWIDTH_LIMIT_MB
+run_fio Malloc0
+verify_qos_limits $BANDWIDTH_RESULT $READ_BANDWIDTH_LIMIT
+
+echo "I/O bandwidth limiting tests successful"
+
+iscsicleanup
+$rpc_py iscsi_delete_target_node 'iqn.2016-06.io.spdk:Target1'
+
+rm -f ./local-job0-0-verify.state
+trap - SIGINT SIGTERM EXIT
+killprocess $pid
+
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/rbd/rbd.sh b/src/spdk/test/iscsi_tgt/rbd/rbd.sh
new file mode 100755
index 000000000..060cc7af0
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/rbd/rbd.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+timing_enter rbd_setup
+rbd_setup $TARGET_IP $TARGET_NAMESPACE
+trap 'rbd_cleanup; exit 1' SIGINT SIGTERM EXIT
+timing_exit rbd_setup
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" -m $ISCSI_TEST_CORE_MASK --wait-for-rpc &
+pid=$!
+
+trap 'killprocess $pid; rbd_cleanup; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+rbd_bdev="$($rpc_py bdev_rbd_create $RBD_POOL $RBD_NAME 4096)"
+$rpc_py bdev_get_bdevs
+
+$rpc_py bdev_rbd_resize $rbd_bdev 2000
+num_block=$($rpc_py bdev_get_bdevs | grep num_blocks | sed 's/[^[:digit:]]//g')
+# get the bdev size in MiB.
+total_size=$((num_block * 4096 / 1048576))
+if [ $total_size != 2000 ]; then
+ echo "resize failed."
+ exit 1
+fi
+# "Ceph0:0" ==> use Ceph0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target3 Target3_alias 'Ceph0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 1
+
+trap 'iscsicleanup; killprocess $pid; rbd_cleanup; exit 1' SIGINT SIGTERM EXIT
+
+$fio_py -p iscsi -i 4096 -d 1 -t randrw -r 1 -v
+$fio_py -p iscsi -i 131072 -d 32 -t randrw -r 1 -v
+
+rm -f ./local-job0-0-verify.state
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+$rpc_py bdev_rbd_delete $rbd_bdev
+killprocess $pid
+rbd_cleanup
+
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/reset/reset.sh b/src/spdk/test/iscsi_tgt/reset/reset.sh
new file mode 100755
index 000000000..406a10c45
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/reset/reset.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=512
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+if ! hash sg_reset; then
+ exit 1
+fi
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py iscsi_set_options -o 30 -a 16
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+$rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT
+$rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK
+$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE
+# "Malloc0:0" ==> use Malloc0 blockdev for LUN0
+# "1:2" ==> map PortalGroup1 to InitiatorGroup2
+# "64" ==> iSCSI queue depth 64
+# "-d" ==> disable CHAP authentication
+$rpc_py iscsi_create_target_node Target3 Target3_alias 'Malloc0:0' $PORTAL_TAG:$INITIATOR_TAG 64 -d
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices 1
+
+dev=$(iscsiadm -m session -P 3 | grep "Attached scsi disk" | awk '{print $4}')
+
+$fio_py -p iscsi -i 512 -d 1 -t read -r 60 &
+fiopid=$!
+echo "FIO pid: $fiopid"
+
+trap 'iscsicleanup; killprocess $pid; killprocess $fiopid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+# Do 3 resets while making sure iscsi_tgt and fio are still running
+for i in 1 2 3; do
+ sleep 1
+ kill -s 0 $pid
+ kill -s 0 $fiopid
+ sg_reset -d /dev/$dev
+ sleep 1
+ kill -s 0 $pid
+ kill -s 0 $fiopid
+done
+
+kill $fiopid
+wait $fiopid || true
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+killprocess $pid
+iscsitestfini $1 $2
diff --git a/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.py b/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.py
new file mode 100755
index 000000000..9f8e32909
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.py
@@ -0,0 +1,481 @@
+#!/usr/bin/env python3
+
+
+import os
+import os.path
+import re
+import sys
+import time
+import json
+import random
+from subprocess import check_call, call, check_output, Popen, PIPE, CalledProcessError
+
+if (len(sys.argv) == 8):
+ target_ip = sys.argv[2]
+ initiator_ip = sys.argv[3]
+ port = sys.argv[4]
+ netmask = sys.argv[5]
+ namespace = sys.argv[6]
+ test_type = sys.argv[7]
+
+ns_cmd = 'ip netns exec ' + namespace
+other_ip = '127.0.0.6'
+initiator_name = 'ANY'
+portal_tag = '1'
+initiator_tag = '1'
+
+rpc_param = {
+ 'target_ip': target_ip,
+ 'initiator_ip': initiator_ip,
+ 'port': port,
+ 'initiator_name': initiator_name,
+ 'netmask': netmask,
+ 'lun_total': 3,
+ 'malloc_bdev_size': 64,
+ 'malloc_block_size': 512,
+ 'queue_depth': 64,
+ 'target_name': 'Target3',
+ 'alias_name': 'Target3_alias',
+ 'disable_chap': True,
+ 'mutual_chap': False,
+ 'require_chap': False,
+ 'chap_group': 0,
+ 'header_digest': False,
+ 'data_digest': False,
+ 'log_flag': 'rpc',
+ 'cpumask': 0x1
+}
+
+
+class RpcException(Exception):
+
+ def __init__(self, retval, msg):
+ super(RpcException, self).__init__(msg)
+ self.retval = retval
+ self.message = msg
+
+
+class spdk_rpc(object):
+
+ def __init__(self, rpc_py):
+ self.rpc_py = rpc_py
+
+ def __getattr__(self, name):
+ def call(*args):
+ cmd = "{} {}".format(self.rpc_py, name)
+ for arg in args:
+ cmd += " {}".format(arg)
+ return check_output(cmd, shell=True).decode("utf-8")
+ return call
+
+
+def verify(expr, retcode, msg):
+ if not expr:
+ raise RpcException(retcode, msg)
+
+
+def verify_log_flag_rpc_methods(rpc_py, rpc_param):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.log_get_flags()
+ jsonvalue = json.loads(output)
+ verify(not jsonvalue[rpc_param['log_flag']], 1,
+ "log_get_flags returned {}, expected false".format(jsonvalue))
+ rpc.log_set_flag(rpc_param['log_flag'])
+ output = rpc.log_get_flags()
+ jsonvalue = json.loads(output)
+ verify(jsonvalue[rpc_param['log_flag']], 1,
+ "log_get_flags returned {}, expected true".format(jsonvalue))
+ rpc.log_clear_flag(rpc_param['log_flag'])
+ output = rpc.log_get_flags()
+ jsonvalue = json.loads(output)
+ verify(not jsonvalue[rpc_param['log_flag']], 1,
+ "log_get_flags returned {}, expected false".format(jsonvalue))
+
+ print("verify_log_flag_rpc_methods passed")
+
+
+def verify_iscsi_connection_rpc_methods(rpc_py):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.iscsi_get_connections()
+ jsonvalue = json.loads(output)
+ verify(not jsonvalue, 1,
+ "iscsi_get_connections returned {}, expected empty".format(jsonvalue))
+
+ rpc.bdev_malloc_create(rpc_param['malloc_bdev_size'], rpc_param['malloc_block_size'])
+ rpc.iscsi_create_portal_group(portal_tag, "{}:{}".format(rpc_param['target_ip'], str(rpc_param['port'])))
+ rpc.iscsi_create_initiator_group(initiator_tag, rpc_param['initiator_name'], rpc_param['netmask'])
+
+ lun_mapping = "Malloc" + str(rpc_param['lun_total']) + ":0"
+ net_mapping = portal_tag + ":" + initiator_tag
+ rpc.iscsi_create_target_node(rpc_param['target_name'], rpc_param['alias_name'], lun_mapping,
+ net_mapping, rpc_param['queue_depth'], '-d')
+ check_output('iscsiadm -m discovery -t st -p {}'.format(rpc_param['target_ip']), shell=True)
+ check_output('iscsiadm -m node --login', shell=True)
+ name = json.loads(rpc.iscsi_get_target_nodes())[0]['name']
+ output = rpc.iscsi_get_connections()
+ jsonvalues = json.loads(output)
+ verify(jsonvalues[0]['target_node_name'] == rpc_param['target_name'], 1,
+ "target node name vaule is {}, expected {}".format(jsonvalues[0]['target_node_name'], rpc_param['target_name']))
+ verify(jsonvalues[0]['initiator_addr'] == rpc_param['initiator_ip'], 1,
+ "initiator address values is {}, expected {}".format(jsonvalues[0]['initiator_addr'], rpc_param['initiator_ip']))
+ verify(jsonvalues[0]['target_addr'] == rpc_param['target_ip'], 1,
+ "target address values is {}, expected {}".format(jsonvalues[0]['target_addr'], rpc_param['target_ip']))
+
+ check_output('iscsiadm -m node --logout', shell=True)
+ check_output('iscsiadm -m node -o delete', shell=True)
+ rpc.iscsi_delete_initiator_group(initiator_tag)
+ rpc.iscsi_delete_portal_group(portal_tag)
+ rpc.iscsi_delete_target_node(name)
+ output = rpc.iscsi_get_connections()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "iscsi_get_connections returned {}, expected empty".format(jsonvalues))
+
+ print("verify_iscsi_connection_rpc_methods passed")
+
+
+def verify_scsi_devices_rpc_methods(rpc_py):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.scsi_get_devices()
+ jsonvalue = json.loads(output)
+ verify(not jsonvalue, 1,
+ "scsi_get_devices returned {}, expected empty".format(jsonvalue))
+
+ rpc.bdev_malloc_create(rpc_param['malloc_bdev_size'], rpc_param['malloc_block_size'])
+ rpc.iscsi_create_portal_group(portal_tag, "{}:{}".format(rpc_param['target_ip'], str(rpc_param['port'])))
+ rpc.iscsi_create_initiator_group(initiator_tag, rpc_param['initiator_name'], rpc_param['netmask'])
+
+ lun_mapping = "Malloc" + str(rpc_param['lun_total']) + ":0"
+ net_mapping = portal_tag + ":" + initiator_tag
+ rpc.iscsi_create_target_node(rpc_param['target_name'], rpc_param['alias_name'], lun_mapping,
+ net_mapping, rpc_param['queue_depth'], '-d')
+ check_output('iscsiadm -m discovery -t st -p {}'.format(rpc_param['target_ip']), shell=True)
+ check_output('iscsiadm -m node --login', shell=True)
+ name = json.loads(rpc.iscsi_get_target_nodes())[0]['name']
+ output = rpc.iscsi_get_options()
+ jsonvalues = json.loads(output)
+ nodebase = jsonvalues['node_base']
+ output = rpc.scsi_get_devices()
+ jsonvalues = json.loads(output)
+ verify(jsonvalues[0]['device_name'] == nodebase + ":" + rpc_param['target_name'], 1,
+ "device name vaule is {}, expected {}".format(jsonvalues[0]['device_name'], rpc_param['target_name']))
+ verify(jsonvalues[0]['id'] == 0, 1,
+ "device id value is {}, expected 0".format(jsonvalues[0]['id']))
+
+ check_output('iscsiadm -m node --logout', shell=True)
+ check_output('iscsiadm -m node -o delete', shell=True)
+ rpc.iscsi_delete_initiator_group(initiator_tag)
+ rpc.iscsi_delete_portal_group(portal_tag)
+ rpc.iscsi_delete_target_node(name)
+ output = rpc.scsi_get_devices()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "scsi_get_devices returned {}, expected empty".format(jsonvalues))
+
+ print("verify_scsi_devices_rpc_methods passed")
+
+
+def create_malloc_bdevs_rpc_methods(rpc_py, rpc_param):
+ rpc = spdk_rpc(rpc_py)
+
+ for i in range(1, rpc_param['lun_total'] + 1):
+ rpc.bdev_malloc_create(rpc_param['malloc_bdev_size'], rpc_param['malloc_block_size'])
+
+ print("create_malloc_bdevs_rpc_methods passed")
+
+
+def verify_portal_groups_rpc_methods(rpc_py, rpc_param):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.iscsi_get_portal_groups()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "iscsi_get_portal_groups returned {} groups, expected empty".format(jsonvalues))
+
+ lo_ip = (target_ip, other_ip)
+ nics = json.loads(rpc.net_get_interfaces())
+ for x in nics:
+ if x["ifc_index"] == 'lo':
+ rpc.net_interface_add_ip_address(x["ifc_index"], lo_ip[1])
+ for idx, value in enumerate(lo_ip):
+ # The portal group tag must start at 1
+ tag = idx + 1
+ rpc.iscsi_create_portal_group(tag, "{}:{}".format(value, rpc_param['port']))
+ output = rpc.iscsi_get_portal_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == tag, 1,
+ "iscsi_get_portal_groups returned {} groups, expected {}".format(len(jsonvalues), tag))
+
+ tag_list = []
+ for idx, value in enumerate(jsonvalues):
+ verify(value['portals'][0]['host'] == lo_ip[idx], 1,
+ "host value is {}, expected {}".format(value['portals'][0]['host'], rpc_param['target_ip']))
+ verify(value['portals'][0]['port'] == str(rpc_param['port']), 1,
+ "port value is {}, expected {}".format(value['portals'][0]['port'], str(rpc_param['port'])))
+ tag_list.append(value['tag'])
+ verify(value['tag'] == idx + 1, 1,
+ "tag value is {}, expected {}".format(value['tag'], idx + 1))
+
+ for idx, value in enumerate(tag_list):
+ rpc.iscsi_delete_portal_group(value)
+ output = rpc.iscsi_get_portal_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == (len(tag_list) - (idx + 1)), 1,
+ "get_portal_group returned {} groups, expected {}".format(len(jsonvalues), (len(tag_list) - (idx + 1))))
+ if not jsonvalues:
+ break
+
+ for jidx, jvalue in enumerate(jsonvalues):
+ verify(jvalue['portals'][0]['host'] == lo_ip[idx + jidx + 1], 1,
+ "host value is {}, expected {}".format(jvalue['portals'][0]['host'], lo_ip[idx + jidx + 1]))
+ verify(jvalue['portals'][0]['port'] == str(rpc_param['port']), 1,
+ "port value is {}, expected {}".format(jvalue['portals'][0]['port'], str(rpc_param['port'])))
+ verify(jvalue['tag'] != value or jvalue['tag'] == tag_list[idx + jidx + 1], 1,
+ "tag value is {}, expected {} and not {}".format(jvalue['tag'], tag_list[idx + jidx + 1], value))
+
+ for x in nics:
+ if x["ifc_index"] == 'lo':
+ rpc.net_interface_delete_ip_address(x["ifc_index"], lo_ip[1])
+
+ print("verify_portal_groups_rpc_methods passed")
+
+
+def verify_initiator_groups_rpc_methods(rpc_py, rpc_param):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.iscsi_get_initiator_groups()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "iscsi_get_initiator_groups returned {}, expected empty".format(jsonvalues))
+ for idx, value in enumerate(rpc_param['netmask']):
+ # The initiator group tag must start at 1
+ tag = idx + 1
+ rpc.iscsi_create_initiator_group(tag, rpc_param['initiator_name'], value)
+ output = rpc.iscsi_get_initiator_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == tag, 1,
+ "iscsi_get_initiator_groups returned {} groups, expected {}".format(len(jsonvalues), tag))
+
+ tag_list = []
+ for idx, value in enumerate(jsonvalues):
+ verify(value['initiators'][0] == rpc_param['initiator_name'], 1,
+ "initiator value is {}, expected {}".format(value['initiators'][0], rpc_param['initiator_name']))
+ tag_list.append(value['tag'])
+ verify(value['tag'] == idx + 1, 1,
+ "tag value is {}, expected {}".format(value['tag'], idx + 1))
+ verify(value['netmasks'][0] == rpc_param['netmask'][idx], 1,
+ "netmasks value is {}, expected {}".format(value['netmasks'][0], rpc_param['netmask'][idx]))
+
+ for idx, value in enumerate(rpc_param['netmask']):
+ tag = idx + 1
+ rpc.iscsi_initiator_group_remove_initiators(tag, '-n', rpc_param['initiator_name'], '-m', value)
+
+ output = rpc.iscsi_get_initiator_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == tag, 1,
+ "iscsi_get_initiator_groups returned {} groups, expected {}".format(len(jsonvalues), tag))
+
+ for idx, value in enumerate(jsonvalues):
+ verify(value['tag'] == idx + 1, 1,
+ "tag value is {}, expected {}".format(value['tag'], idx + 1))
+ initiators = value.get('initiators')
+ verify(len(initiators) == 0, 1,
+ "length of initiator list is {}, expected 0".format(len(initiators)))
+ netmasks = value.get('netmasks')
+ verify(len(netmasks) == 0, 1,
+ "length of netmask list is {}, expected 0".format(len(netmasks)))
+
+ for idx, value in enumerate(rpc_param['netmask']):
+ tag = idx + 1
+ rpc.iscsi_initiator_group_add_initiators(tag, '-n', rpc_param['initiator_name'], '-m', value)
+ output = rpc.iscsi_get_initiator_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == tag, 1,
+ "iscsi_get_initiator_groups returned {} groups, expected {}".format(len(jsonvalues), tag))
+
+ tag_list = []
+ for idx, value in enumerate(jsonvalues):
+ verify(value['initiators'][0] == rpc_param['initiator_name'], 1,
+ "initiator value is {}, expected {}".format(value['initiators'][0], rpc_param['initiator_name']))
+ tag_list.append(value['tag'])
+ verify(value['tag'] == idx + 1, 1,
+ "tag value is {}, expected {}".format(value['tag'], idx + 1))
+ verify(value['netmasks'][0] == rpc_param['netmask'][idx], 1,
+ "netmasks value is {}, expected {}".format(value['netmasks'][0], rpc_param['netmask'][idx]))
+
+ for idx, value in enumerate(tag_list):
+ rpc.iscsi_delete_initiator_group(value)
+ output = rpc.iscsi_get_initiator_groups()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == (len(tag_list) - (idx + 1)), 1,
+ "iscsi_get_initiator_groups returned {} groups, expected {}".format(len(jsonvalues), (len(tag_list) - (idx + 1))))
+ if not jsonvalues:
+ break
+ for jidx, jvalue in enumerate(jsonvalues):
+ verify(jvalue['initiators'][0] == rpc_param['initiator_name'], 1,
+ "initiator value is {}, expected {}".format(jvalue['initiators'][0], rpc_param['initiator_name']))
+ verify(jvalue['tag'] != value or jvalue['tag'] == tag_list[idx + jidx + 1], 1,
+ "tag value is {}, expected {} and not {}".format(jvalue['tag'], tag_list[idx + jidx + 1], value))
+ verify(jvalue['netmasks'][0] == rpc_param['netmask'][idx + jidx + 1], 1,
+ "netmasks value is {}, expected {}".format(jvalue['netmasks'][0], rpc_param['netmask'][idx + jidx + 1]))
+
+ print("verify_initiator_groups_rpc_method passed.")
+
+
+def verify_target_nodes_rpc_methods(rpc_py, rpc_param):
+ rpc = spdk_rpc(rpc_py)
+ output = rpc.iscsi_get_options()
+ jsonvalues = json.loads(output)
+ nodebase = jsonvalues['node_base']
+ output = rpc.iscsi_get_target_nodes()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "iscsi_get_target_nodes returned {}, expected empty".format(jsonvalues))
+
+ rpc.bdev_malloc_create(rpc_param['malloc_bdev_size'], rpc_param['malloc_block_size'])
+ rpc.iscsi_create_portal_group(portal_tag, "{}:{}".format(rpc_param['target_ip'], str(rpc_param['port'])))
+ rpc.iscsi_create_initiator_group(initiator_tag, rpc_param['initiator_name'], rpc_param['netmask'])
+
+ lun_mapping = "Malloc" + str(rpc_param['lun_total']) + ":0"
+ net_mapping = portal_tag + ":" + initiator_tag
+ rpc.iscsi_create_target_node(rpc_param['target_name'], rpc_param['alias_name'], lun_mapping,
+ net_mapping, rpc_param['queue_depth'], '-d')
+ output = rpc.iscsi_get_target_nodes()
+ jsonvalues = json.loads(output)
+ verify(len(jsonvalues) == 1, 1,
+ "iscsi_get_target_nodes returned {} nodes, expected 1".format(len(jsonvalues)))
+ bdev_name = jsonvalues[0]['luns'][0]['bdev_name']
+ verify(bdev_name == "Malloc" + str(rpc_param['lun_total']), 1,
+ "bdev_name value is {}, expected Malloc{}".format(jsonvalues[0]['luns'][0]['bdev_name'], str(rpc_param['lun_total'])))
+ name = jsonvalues[0]['name']
+ verify(name == nodebase + ":" + rpc_param['target_name'], 1,
+ "target name value is {}, expected {}".format(name, nodebase + ":" + rpc_param['target_name']))
+ verify(jsonvalues[0]['alias_name'] == rpc_param['alias_name'], 1,
+ "target alias_name value is {}, expected {}".format(jsonvalues[0]['alias_name'], rpc_param['alias_name']))
+ verify(jsonvalues[0]['luns'][0]['lun_id'] == 0, 1,
+ "lun id value is {}, expected 0".format(jsonvalues[0]['luns'][0]['lun_id']))
+ verify(jsonvalues[0]['pg_ig_maps'][0]['ig_tag'] == int(initiator_tag), 1,
+ "initiator group tag value is {}, expected {}".format(jsonvalues[0]['pg_ig_maps'][0]['ig_tag'], initiator_tag))
+ verify(jsonvalues[0]['queue_depth'] == rpc_param['queue_depth'], 1,
+ "queue depth value is {}, expected {}".format(jsonvalues[0]['queue_depth'], rpc_param['queue_depth']))
+ verify(jsonvalues[0]['pg_ig_maps'][0]['pg_tag'] == int(portal_tag), 1,
+ "portal group tag value is {}, expected {}".format(jsonvalues[0]['pg_ig_maps'][0]['pg_tag'], portal_tag))
+ verify(jsonvalues[0]['disable_chap'] == rpc_param['disable_chap'], 1,
+ "disable chap value is {}, expected {}".format(jsonvalues[0]['disable_chap'], rpc_param['disable_chap']))
+ verify(jsonvalues[0]['mutual_chap'] == rpc_param['mutual_chap'], 1,
+ "chap mutual value is {}, expected {}".format(jsonvalues[0]['mutual_chap'], rpc_param['mutual_chap']))
+ verify(jsonvalues[0]['require_chap'] == rpc_param['require_chap'], 1,
+ "chap required value is {}, expected {}".format(jsonvalues[0]['require_chap'], rpc_param['require_chap']))
+ verify(jsonvalues[0]['chap_group'] == rpc_param['chap_group'], 1,
+ "chap auth group value is {}, expected {}".format(jsonvalues[0]['chap_group'], rpc_param['chap_group']))
+ verify(jsonvalues[0]['header_digest'] == rpc_param['header_digest'], 1,
+ "header digest value is {}, expected {}".format(jsonvalues[0]['header_digest'], rpc_param['header_digest']))
+ verify(jsonvalues[0]['data_digest'] == rpc_param['data_digest'], 1,
+ "data digest value is {}, expected {}".format(jsonvalues[0]['data_digest'], rpc_param['data_digest']))
+ lun_id = '1'
+ rpc.iscsi_target_node_add_lun(name, bdev_name, "-i", lun_id)
+ output = rpc.iscsi_get_target_nodes()
+ jsonvalues = json.loads(output)
+ verify(jsonvalues[0]['luns'][1]['bdev_name'] == "Malloc" + str(rpc_param['lun_total']), 1,
+ "bdev_name value is {}, expected Malloc{}".format(jsonvalues[0]['luns'][0]['bdev_name'], str(rpc_param['lun_total'])))
+ verify(jsonvalues[0]['luns'][1]['lun_id'] == 1, 1,
+ "lun id value is {}, expected 1".format(jsonvalues[0]['luns'][1]['lun_id']))
+
+ rpc.iscsi_delete_target_node(name)
+ output = rpc.iscsi_get_target_nodes()
+ jsonvalues = json.loads(output)
+ verify(not jsonvalues, 1,
+ "iscsi_get_target_nodes returned {}, expected empty".format(jsonvalues))
+
+ rpc.iscsi_create_target_node(rpc_param['target_name'], rpc_param['alias_name'], lun_mapping,
+ net_mapping, rpc_param['queue_depth'], '-d')
+
+ rpc.iscsi_delete_portal_group(portal_tag)
+ rpc.iscsi_delete_initiator_group(initiator_tag)
+ rpc.iscsi_delete_target_node(name)
+ output = rpc.iscsi_get_target_nodes()
+ jsonvalues = json.loads(output)
+ if not jsonvalues:
+ print("This issue will be fixed later.")
+
+ print("verify_target_nodes_rpc_methods passed.")
+
+
+def verify_net_get_interfaces(rpc_py):
+ rpc = spdk_rpc(rpc_py)
+ nics = json.loads(rpc.net_get_interfaces())
+ nics_names = set(x["name"] for x in nics)
+ # parse ip link show to verify the net_get_interfaces result
+ ip_show = ns_cmd + " ip link show"
+ ifcfg_nics = set(re.findall(r'\S+:\s(\S+?)(?:@\S+){0,1}:\s<.*', check_output(ip_show.split()).decode()))
+ verify(nics_names == ifcfg_nics, 1, "net_get_interfaces returned {}".format(nics))
+ print("verify_net_get_interfaces passed.")
+
+
+def help_get_interface_ip_list(rpc_py, nic_name):
+ rpc = spdk_rpc(rpc_py)
+ nics = json.loads(rpc.net_get_interfaces())
+ nic = list([x for x in nics if x["name"] == nic_name])
+ verify(len(nic) != 0, 1,
+ "Nic name: {} is not found in {}".format(nic_name, [x["name"] for x in nics]))
+ return nic[0]["ip_addr"]
+
+
+def verify_net_interface_add_delete_ip_address(rpc_py):
+ rpc = spdk_rpc(rpc_py)
+ nics = json.loads(rpc.net_get_interfaces())
+ # add ip on up to first 2 nics
+ for x in nics[:2]:
+ faked_ip = "123.123.{}.{}".format(random.randint(1, 254), random.randint(1, 254))
+ ping_cmd = ns_cmd + " ping -c 1 -W 1 " + faked_ip
+ rpc.net_interface_add_ip_address(x["ifc_index"], faked_ip)
+ verify(faked_ip in help_get_interface_ip_list(rpc_py, x["name"]), 1,
+ "add ip {} to nic {} failed.".format(faked_ip, x["name"]))
+ try:
+ check_call(ping_cmd.split())
+ except BaseException:
+ verify(False, 1,
+ "ping ip {} for {} was failed(adding was successful)".format
+ (faked_ip, x["name"]))
+ rpc.net_interface_delete_ip_address(x["ifc_index"], faked_ip)
+ verify(faked_ip not in help_get_interface_ip_list(rpc_py, x["name"]), 1,
+ "delete ip {} from nic {} failed.(adding and ping were successful)".format
+ (faked_ip, x["name"]))
+ # ping should be failed and throw an CalledProcessError exception
+ try:
+ check_call(ping_cmd.split())
+ except CalledProcessError as _:
+ pass
+ except Exception as e:
+ verify(False, 1,
+ "Unexpected exception was caught {}(adding/ping/delete were successful)".format
+ (str(e)))
+ else:
+ verify(False, 1,
+ "ip {} for {} could be pinged after delete ip(adding/ping/delete were successful)".format
+ (faked_ip, x["name"]))
+ print("verify_net_interface_add_delete_ip_address passed.")
+
+
+if __name__ == "__main__":
+
+ rpc_py = sys.argv[1]
+
+ try:
+ verify_log_flag_rpc_methods(rpc_py, rpc_param)
+ verify_net_get_interfaces(rpc_py)
+ # Add/delete IP will not be supported in VPP.
+ # It has separate vppctl utility for that.
+ if test_type == 'posix':
+ verify_net_interface_add_delete_ip_address(rpc_py)
+ create_malloc_bdevs_rpc_methods(rpc_py, rpc_param)
+ verify_portal_groups_rpc_methods(rpc_py, rpc_param)
+ verify_initiator_groups_rpc_methods(rpc_py, rpc_param)
+ verify_target_nodes_rpc_methods(rpc_py, rpc_param)
+ verify_scsi_devices_rpc_methods(rpc_py)
+ verify_iscsi_connection_rpc_methods(rpc_py)
+ except RpcException as e:
+ print("{}. Exiting with status {}".format(e.message, e.retval))
+ raise e
+ except Exception as e:
+ raise e
+
+ sys.exit(0)
diff --git a/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.sh b/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.sh
new file mode 100755
index 000000000..ce54b4ab2
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/rpc_config/rpc_config.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = test type posix or vpp.
+# $2 = "iso" - triggers isolation mode (setting up required environment).
+iscsitestinit $2 $1
+
+if [ "$1" == "posix" ] || [ "$1" == "vpp" ]; then
+ TEST_TYPE=$1
+else
+ echo "No iSCSI test type specified"
+ exit 1
+fi
+
+MALLOC_BDEV_SIZE=64
+
+rpc_py=$rootdir/scripts/rpc.py
+rpc_config_py="$testdir/rpc_config.py"
+
+timing_enter start_iscsi_tgt
+
+"${ISCSI_APP[@]}" --wait-for-rpc &
+pid=$!
+echo "Process pid: $pid"
+
+trap 'killprocess $pid; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $pid
+$rpc_py framework_wait_init &
+rpc_wait_pid=$!
+$rpc_py iscsi_set_options -o 30 -a 16
+
+# RPC framework_wait_init should be blocked, so its process must be existed
+ps $rpc_wait_pid
+
+$rpc_py framework_start_init
+echo "iscsi_tgt is listening. Running tests..."
+
+# RPC framework_wait_init should be already returned, so its process must be non-existed
+! ps $rpc_wait_pid
+
+# RPC framework_wait_init will directly returned after subsystem initialized.
+$rpc_py framework_wait_init &
+rpc_wait_pid=$!
+sleep 1
+! ps $rpc_wait_pid
+
+timing_exit start_iscsi_tgt
+
+$rpc_config_py $rpc_py $TARGET_IP $INITIATOR_IP $ISCSI_PORT $NETMASK $TARGET_NAMESPACE $TEST_TYPE
+
+$rpc_py bdev_get_bdevs
+
+trap - SIGINT SIGTERM EXIT
+
+iscsicleanup
+killprocess $pid
+
+iscsitestfini $2 $1
diff --git a/src/spdk/test/iscsi_tgt/sock/sock.sh b/src/spdk/test/iscsi_tgt/sock/sock.sh
new file mode 100755
index 000000000..14615d3bc
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/sock/sock.sh
@@ -0,0 +1,142 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+function waitfortcp() {
+ local addr="$2"
+
+ if hash ip &> /dev/null; then
+ local have_ip_cmd=true
+ else
+ local have_ip_cmd=false
+ fi
+
+ if hash ss &> /dev/null; then
+ local have_ss_cmd=true
+ else
+ local have_ss_cmd=false
+ fi
+
+ echo "Waiting for process to start up and listen on address $addr..."
+ # turn off trace for this loop
+ xtrace_disable
+ local ret=0
+ local i
+ for ((i = 40; i != 0; i--)); do
+ # if the process is no longer running, then exit the script
+ # since it means the application crashed
+ if ! kill -s 0 $1; then
+ echo "ERROR: process (pid: $1) is no longer running"
+ ret=1
+ break
+ fi
+
+ if $have_ip_cmd; then
+ namespace=$(ip netns identify $1)
+ if [ -n "$namespace" ]; then
+ ns_cmd="ip netns exec $namespace"
+ fi
+ fi
+
+ if $have_ss_cmd; then
+ if $ns_cmd ss -ln | grep -E -q "\s+$addr\s+"; then
+ break
+ fi
+ elif [[ "$(uname -s)" == "Linux" ]]; then
+ # For Linux, if system doesn't have ss, just assume it has netstat
+ if $ns_cmd netstat -an | grep -iw LISTENING | grep -E -q "\s+$addr\$"; then
+ break
+ fi
+ fi
+ sleep 0.5
+ done
+
+ xtrace_restore
+ if ((i == 0)); then
+ echo "ERROR: timeout while waiting for process (pid: $1) to start listening on '$addr'"
+ ret=1
+ fi
+ return $ret
+}
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+if [ "$1" == "iso" ]; then
+ TEST_TYPE=$2
+else
+ TEST_TYPE=$1
+fi
+
+if [ -z "$TEST_TYPE" ]; then
+ TEST_TYPE="posix"
+fi
+
+if [ "$TEST_TYPE" != "posix" ] && [ "$TEST_TYPE" != "vpp" ]; then
+ echo "No correct sock implmentation specified"
+ exit 1
+fi
+
+HELLO_SOCK_APP="${TARGET_NS_CMD[*]} $SPDK_EXAMPLE_DIR/hello_sock"
+if [ $SPDK_TEST_VPP -eq 1 ]; then
+ HELLO_SOCK_APP+=" -L sock_vpp"
+fi
+SOCAT_APP="socat"
+
+# ----------------
+# Test client path
+# ----------------
+timing_enter sock_client
+echo "Testing client path"
+
+# start echo server using socat
+$SOCAT_APP tcp-l:$ISCSI_PORT,fork,bind=$INITIATOR_IP exec:'/bin/cat' &
+server_pid=$!
+trap 'killprocess $server_pid;iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitfortcp $server_pid $INITIATOR_IP:$ISCSI_PORT
+
+# send message using hello_sock client
+message="**MESSAGE:This is a test message from the client**"
+response=$(echo $message | $HELLO_SOCK_APP -H $INITIATOR_IP -P $ISCSI_PORT -N $TEST_TYPE)
+
+if ! echo "$response" | grep -q "$message"; then
+ exit 1
+fi
+
+trap '-' SIGINT SIGTERM EXIT
+# NOTE: socat returns code 143 on SIGINT
+killprocess $server_pid || true
+
+timing_exit sock_client
+
+# ----------------
+# Test server path
+# ----------------
+
+timing_enter sock_server
+
+# start echo server using hello_sock echo server
+$HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT -S -N $TEST_TYPE &
+server_pid=$!
+trap 'killprocess $server_pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+waitforlisten $server_pid
+
+# send message to server using socat
+message="**MESSAGE:This is a test message to the server**"
+response=$(echo $message | $SOCAT_APP - tcp:$TARGET_IP:$ISCSI_PORT 2> /dev/null)
+
+if [ "$message" != "$response" ]; then
+ exit 1
+fi
+
+trap - SIGINT SIGTERM EXIT
+
+killprocess $server_pid
+
+iscsitestfini $1 $2
+timing_exit sock_server
diff --git a/src/spdk/test/iscsi_tgt/trace_record/trace_record.sh b/src/spdk/test/iscsi_tgt/trace_record/trace_record.sh
new file mode 100755
index 000000000..baa7f39d4
--- /dev/null
+++ b/src/spdk/test/iscsi_tgt/trace_record/trace_record.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+
+testdir=$(readlink -f $(dirname $0))
+rootdir=$(readlink -f $testdir/../../..)
+source $rootdir/test/common/autotest_common.sh
+source $rootdir/test/iscsi_tgt/common.sh
+
+# $1 = "iso" - triggers isolation mode (setting up required environment).
+# $2 = test type posix or vpp. defaults to posix.
+iscsitestinit $1 $2
+
+TRACE_TMP_FOLDER=./tmp-trace
+TRACE_RECORD_OUTPUT=${TRACE_TMP_FOLDER}/record.trace
+TRACE_RECORD_NOTICE_LOG=${TRACE_TMP_FOLDER}/record.notice
+TRACE_TOOL_LOG=${TRACE_TMP_FOLDER}/trace.log
+
+delete_tmp_files() {
+ rm -rf $TRACE_TMP_FOLDER
+}
+
+if [ -z "$TARGET_IP" ]; then
+ echo "TARGET_IP not defined in environment"
+ exit 1
+fi
+
+if [ -z "$INITIATOR_IP" ]; then
+ echo "INITIATOR_IP not defined in environment"
+ exit 1
+fi
+
+NUM_TRACE_ENTRIES=4096
+MALLOC_BDEV_SIZE=64
+MALLOC_BLOCK_SIZE=4096
+
+rpc_py="$rootdir/scripts/rpc.py"
+fio_py="$rootdir/scripts/fio.py"
+
+timing_enter start_iscsi_tgt
+
+echo "start iscsi_tgt with trace enabled"
+"${ISCSI_APP[@]}" -m 0xf --num-trace-entries $NUM_TRACE_ENTRIES --tpoint-group-mask 0xf &
+iscsi_pid=$!
+echo "Process pid: $iscsi_pid"
+
+trap 'killprocess $iscsi_pid; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+waitforlisten $iscsi_pid
+
+echo "iscsi_tgt is listening. Running tests..."
+
+timing_exit start_iscsi_tgt
+
+mkdir -p ${TRACE_TMP_FOLDER}
+./build/bin/spdk_trace_record -s iscsi -p ${iscsi_pid} -f ${TRACE_RECORD_OUTPUT} -q 1> ${TRACE_RECORD_NOTICE_LOG} &
+record_pid=$!
+echo "Trace record pid: $record_pid"
+
+RPCS=
+RPCS+="iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT\n"
+RPCS+="iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK\n"
+
+echo "Create bdevs and target nodes"
+CONNECTION_NUMBER=15
+for i in $(seq 0 $CONNECTION_NUMBER); do
+ RPCS+="bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE -b Malloc$i\n"
+ RPCS+="iscsi_create_target_node Target$i Target${i}_alias "Malloc$i:0" $PORTAL_TAG:$INITIATOR_TAG 256 -d\n"
+done
+echo -e $RPCS | $rpc_py
+
+sleep 1
+
+iscsiadm -m discovery -t sendtargets -p $TARGET_IP:$ISCSI_PORT
+iscsiadm -m node --login -p $TARGET_IP:$ISCSI_PORT
+waitforiscsidevices $((CONNECTION_NUMBER + 1))
+
+trap 'iscsicleanup; killprocess $iscsi_pid; killprocess $record_pid; delete_tmp_files; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+echo "Running FIO"
+$fio_py -p iscsi -i 131072 -d 32 -t randrw -r 1
+
+iscsicleanup
+
+RPCS=
+# Delete Malloc blockdevs and targets
+for i in $(seq 0 $CONNECTION_NUMBER); do
+ RPCS+="iscsi_delete_target_node iqn.2016-06.io.spdk:Target$i\n"
+ RPCS+="bdev_malloc_delete Malloc$i\n"
+done
+echo -e $RPCS | $rpc_py
+
+trap 'delete_tmp_files; iscsitestfini $1 $2; exit 1' SIGINT SIGTERM EXIT
+
+killprocess $iscsi_pid
+killprocess $record_pid
+./build/bin/spdk_trace -f ${TRACE_RECORD_OUTPUT} > ${TRACE_TOOL_LOG}
+
+#verify trace record and trace tool
+#trace entries str in trace-record, like "Trace Size of lcore (0): 4136"
+record_num="$(grep "trace entries for lcore" ${TRACE_RECORD_NOTICE_LOG} | cut -d ' ' -f 2)"
+
+#trace entries str in trace-tool, like "Port 4096 trace entries for lcore (0) in 441871 msec"
+trace_tool_num="$(grep "Trace Size of lcore" ${TRACE_TOOL_LOG} | cut -d ' ' -f 6)"
+
+delete_tmp_files
+
+echo "entries numbers from trace record are:" $record_num
+echo "entries numbers from trace tool are:" $trace_tool_num
+
+arr_record_num=($record_num)
+arr_trace_tool_num=($trace_tool_num)
+len_arr_record_num=${#arr_record_num[@]}
+len_arr_trace_tool_num=${#arr_trace_tool_num[@]}
+
+#lcore num check
+if [ $len_arr_record_num -ne $len_arr_trace_tool_num ]; then
+ echo "trace record test on iscsi: failure on lcore number check"
+ set -e
+ exit 1
+fi
+#trace entries num check
+for i in $(seq 0 $((len_arr_record_num - 1))); do
+ if [ ${arr_record_num[$i]} -le ${NUM_TRACE_ENTRIES} ]; then
+ echo "trace record test on iscsi: failure on inefficient entries number check"
+ set -e
+ exit 1
+ fi
+ if [ ${arr_record_num[$i]} -ne ${arr_trace_tool_num[$i]} ]; then
+ echo "trace record test on iscsi: failure on entries number check"
+ set -e
+ exit 1
+ fi
+done
+
+trap - SIGINT SIGTERM EXIT
+iscsitestfini $1 $2