diff --git a/CHANGELOG.md b/CHANGELOG.md index 007fc4470..ffbb82fc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,12 +32,19 @@ The HotplugEnable option in `[Nvme]` sections of the configuration file is now The NVMe library now includes a function spdk_nvme_ns_get_ctrlr which returns the NVMe Controller associated with a given namespace. -### NVMe-oF Target (nvmf) +### NVMe-oF Target (nvmf_tgt) The NVMe-oF target no longer requires any in capsule data buffers to run, and the feature is now entirely optional. Previously, at least 4KiB in capsule data buffers were required. +NVMe-oF subsytems have a new configuration option, AllowAnyHost, to control +whether the host NQN whitelist is enforced when accepting new connections. +If no Host options have been specified and AllowAnyHost is disabled, the +connection will be denied; this is a behavior change from previous releases, +which allowed any host NQN to connect if the Host list was empty. +AllowAnyHost is disabled by default. + ### Environment Abstraction Layer A new default value, SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, was added to provide diff --git a/app/nvmf_tgt/conf.c b/app/nvmf_tgt/conf.c index 6da62bba7..d8f472250 100644 --- a/app/nvmf_tgt/conf.c +++ b/app/nvmf_tgt/conf.c @@ -124,6 +124,7 @@ spdk_add_nvmf_discovery_subsystem(void) return -1; } + spdk_nvmf_subsystem_set_allow_any_host(app_subsys->subsystem, true); nvmf_tgt_start_subsystem(app_subsys); return 0; @@ -230,6 +231,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) char *listen_addrs_str[MAX_LISTEN_ADDRESSES] = {}; int num_hosts; char *hosts[MAX_HOSTS]; + bool allow_any_host; const char *sn; int num_devs; char *devs[MAX_NAMESPACES]; @@ -290,6 +292,8 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) } num_hosts = i; + allow_any_host = spdk_conf_section_get_boolval(sp, "AllowAnyHost", false); + sn = spdk_conf_section_get_val(sp, "SN"); num_devs = 0; @@ -304,7 +308,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp) ret = spdk_nvmf_construct_subsystem(nqn, lcore, num_listen_addrs, listen_addrs, - num_hosts, hosts, + num_hosts, hosts, allow_any_host, sn, num_devs, devs); @@ -357,7 +361,7 @@ spdk_nvmf_parse_conf(void) int spdk_nvmf_construct_subsystem(const char *name, int32_t lcore, int num_listen_addresses, struct rpc_listen_address *addresses, - int num_hosts, char *hosts[], + int num_hosts, char *hosts[], bool allow_any_host, const char *sn, int num_devs, char *dev_list[]) { struct spdk_nvmf_subsystem *subsystem; @@ -444,6 +448,7 @@ spdk_nvmf_construct_subsystem(const char *name, int32_t lcore, for (i = 0; i < num_hosts; i++) { spdk_nvmf_subsystem_add_host(subsystem, hosts[i]); } + spdk_nvmf_subsystem_set_allow_any_host(subsystem, allow_any_host); if (sn == NULL) { SPDK_ERRLOG("Subsystem %s: missing serial number\n", name); diff --git a/app/nvmf_tgt/nvmf_rpc.c b/app/nvmf_tgt/nvmf_rpc.c index dda2cbde1..5f0cfc27b 100644 --- a/app/nvmf_tgt/nvmf_rpc.c +++ b/app/nvmf_tgt/nvmf_rpc.c @@ -89,6 +89,9 @@ dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct nvmf_tgt_subsystem *tg } spdk_json_write_array_end(w); + spdk_json_write_name(w, "allow_any_host"); + spdk_json_write_bool(w, spdk_nvmf_subsystem_get_allow_any_host(subsystem)); + spdk_json_write_name(w, "hosts"); spdk_json_write_array_begin(w); @@ -261,6 +264,7 @@ struct rpc_subsystem { char *nqn; struct rpc_listen_addresses listen_addresses; struct rpc_hosts hosts; + bool allow_any_host; char *pci_address; char *serial_number; struct rpc_dev_names namespaces; @@ -283,6 +287,7 @@ static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = { {"nqn", offsetof(struct rpc_subsystem, nqn), spdk_json_decode_string}, {"listen_addresses", offsetof(struct rpc_subsystem, listen_addresses), decode_rpc_listen_addresses}, {"hosts", offsetof(struct rpc_subsystem, hosts), decode_rpc_hosts, true}, + {"allow_any_host", offsetof(struct rpc_subsystem, allow_any_host), spdk_json_decode_bool, true}, {"serial_number", offsetof(struct rpc_subsystem, serial_number), spdk_json_decode_string, true}, {"namespaces", offsetof(struct rpc_subsystem, namespaces), decode_rpc_dev_names, true}, }; @@ -321,7 +326,7 @@ spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request, ret = spdk_nvmf_construct_subsystem(req.nqn, req.core, req.listen_addresses.num_listen_address, req.listen_addresses.addresses, - req.hosts.num_hosts, req.hosts.hosts, + req.hosts.num_hosts, req.hosts.hosts, req.allow_any_host, req.serial_number, req.namespaces.num_names, req.namespaces.names); if (ret) { diff --git a/app/nvmf_tgt/nvmf_tgt.h b/app/nvmf_tgt/nvmf_tgt.h index fd1726b3b..6f4902c94 100644 --- a/app/nvmf_tgt/nvmf_tgt.h +++ b/app/nvmf_tgt/nvmf_tgt.h @@ -83,7 +83,7 @@ int spdk_nvmf_construct_subsystem(const char *name, int32_t lcore, int num_listen_addresses, struct rpc_listen_address *addresses, - int num_hosts, char *hosts[], + int num_hosts, char *hosts[], bool allow_any_host, const char *sn, int num_devs, char *dev_list[]); int diff --git a/doc/nvmf.md b/doc/nvmf.md index a33ef212e..0a66e923e 100644 --- a/doc/nvmf.md +++ b/doc/nvmf.md @@ -160,6 +160,7 @@ TransportID "trtype:PCIe traddr:0000:82:00.0" Nvme1 NQN nqn.2016-06.io.spdk:cnode1 Core 25 Listen RDMA 192.168.100.8:4420 +AllowAnyHost No Host nqn.2016-06.io.spdk:init SN SPDK00000000000001 Namespace Nvme0n1 @@ -168,6 +169,7 @@ Namespace Nvme0n1 NQN nqn.2016-06.io.spdk:cnode2 Core 26 Listen RDMA 192.168.100.9:4420 +AllowAnyHost Yes SN SPDK00000000000002 Namespace Nvme1n1 ~~~ @@ -193,6 +195,7 @@ virtual controller with two namespaces backed by the malloc LUNs named Malloc0 a NQN nqn.2016-06.io.spdk:cnode2 Core 0 Listen RDMA 192.168.2.21:4420 + AllowAnyHost No Host nqn.2016-06.io.spdk:init SN SPDK00000000000001 Namespace Malloc0 diff --git a/etc/spdk/nvmf.conf.in b/etc/spdk/nvmf.conf.in index 6a13bc8c5..2c8843e57 100644 --- a/etc/spdk/nvmf.conf.in +++ b/etc/spdk/nvmf.conf.in @@ -139,6 +139,7 @@ NQN nqn.2016-06.io.spdk:cnode1 Core 0 Listen RDMA 15.15.15.2:4420 + AllowAnyHost No Host nqn.2016-06.io.spdk:init SN SPDK00000000000001 Namespace Nvme0n1 @@ -150,6 +151,7 @@ NQN nqn.2016-06.io.spdk:cnode2 Core 0 Listen RDMA 192.168.2.21:4420 + AllowAnyHost No Host nqn.2016-06.io.spdk:init SN SPDK00000000000002 Namespace Malloc0 diff --git a/include/spdk/nvmf.h b/include/spdk/nvmf.h index 38e294239..17b9efc60 100644 --- a/include/spdk/nvmf.h +++ b/include/spdk/nvmf.h @@ -135,6 +135,25 @@ void spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem); int spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn); +/** + * Set whether a subsystem should allow any host or only hosts in the allowed list. + * + * \param subsystem Subsystem to modify. + * \param allow_any_host true to allow any host to connect to this subsystem, or false to enforce + * the whitelist configured with spdk_nvmf_subsystem_add_host(). + */ +void spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, + bool allow_any_host); + +/** + * Check whether a subsystem should allow any host or only hosts in the allowed list. + * + * \param subsystem Subsystem to modify. + * \return true if any host is allowed to connect to this subsystem, or false if connecting hosts + * must be in the whitelist configured with spdk_nvmf_subsystem_add_host(). + */ +bool spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem); + /** * Check if the given host is allowed to connect to the subsystem. * diff --git a/lib/nvmf/nvmf_internal.h b/lib/nvmf/nvmf_internal.h index 891177d22..75686d53b 100644 --- a/lib/nvmf/nvmf_internal.h +++ b/lib/nvmf/nvmf_internal.h @@ -176,6 +176,7 @@ struct spdk_nvmf_subsystem { char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1]; enum spdk_nvmf_subtype subtype; bool is_removed; + bool allow_any_host; struct spdk_nvmf_tgt *tgt; diff --git a/lib/nvmf/subsystem.c b/lib/nvmf/subsystem.c index 46776053f..f6dc7badf 100644 --- a/lib/nvmf/subsystem.c +++ b/lib/nvmf/subsystem.c @@ -224,6 +224,18 @@ spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char * return 0; } +void +spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host) +{ + subsystem->allow_any_host = allow_any_host; +} + +bool +spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem) +{ + return subsystem->allow_any_host; +} + bool spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn) { @@ -233,8 +245,7 @@ spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const ch return false; } - if (TAILQ_EMPTY(&subsystem->hosts)) { - /* No hosts means any host can connect */ + if (subsystem->allow_any_host) { return true; } diff --git a/scripts/rpc.py b/scripts/rpc.py index 809127407..877491ae3 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -420,6 +420,9 @@ def construct_nvmf_subsystem(args): hosts.append(u) params['hosts'] = hosts + if args.allow_any_host: + params['allow_any_host'] = True + if args.namespaces: namespaces = [] for u in args.namespaces.strip().split(" "): @@ -437,6 +440,7 @@ Example: 'trtype:RDMA traddr:192.168.100.8 trsvcid:4420,trtype:RDMA traddr:192.1 p.add_argument('hosts', help="""Whitespace-separated list of host nqn list. Format: 'nqn1 nqn2' etc Example: 'nqn.2016-06.io.spdk:init nqn.2016-07.io.spdk:init'""") +p.add_argument("-a", "--allow-any-host", action='store_true', help="Allow any host to connect (don't enforce host NQN whitelist)") p.add_argument("-s", "--serial_number", help=""" Format: 'sn' etc Example: 'SPDK00000000000001'""", default='0000:00:01.0') diff --git a/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh b/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh index d77f97225..081230cd2 100755 --- a/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh +++ b/test/iscsi_tgt/nvme_remote/fio_remote_nvme.sh @@ -31,7 +31,7 @@ trap "killprocess $nvmfpid; exit 1" SIGINT SIGTERM EXIT waitforlisten $nvmfpid 5260 echo "NVMf target has started." bdevs=$($rpc_py construct_malloc_bdev 64 512) -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 -n "$bdevs" echo "NVMf subsystem created." timing_enter start_iscsi_tgt diff --git a/test/nvmf/discovery/discovery.sh b/test/nvmf/discovery/discovery.sh index f482e0857..f8e828dcb 100755 --- a/test/nvmf/discovery/discovery.sh +++ b/test/nvmf/discovery/discovery.sh @@ -40,7 +40,7 @@ bdevs="$bdevs $($rpc_py construct_null_bdev Null1 $NULL_BDEV_SIZE $NULL_BLOCK_SI modprobe -v nvme-rdma -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 -n "$bdevs" nvme discover -t rdma -a $NVMF_FIRST_TARGET_IP -s $NVMF_PORT diff --git a/test/nvmf/filesystem/filesystem.sh b/test/nvmf/filesystem/filesystem.sh index 43a491ac7..b1b8665f2 100755 --- a/test/nvmf/filesystem/filesystem.sh +++ b/test/nvmf/filesystem/filesystem.sh @@ -35,7 +35,7 @@ bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SI modprobe -v nvme-rdma -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 -n "$bdevs" nvme connect -t rdma -n "nqn.2016-06.io.spdk:cnode1" -a "$NVMF_FIRST_TARGET_IP" -s "$NVMF_PORT" diff --git a/test/nvmf/fio/fio.sh b/test/nvmf/fio/fio.sh index a1b5b6a76..3d23d5324 100755 --- a/test/nvmf/fio/fio.sh +++ b/test/nvmf/fio/fio.sh @@ -35,7 +35,7 @@ bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SI modprobe -v nvme-rdma -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" "" -a -s SPDK00000000000001 -n "$bdevs" nvme connect -t rdma -n "nqn.2016-06.io.spdk:cnode1" -a "$NVMF_FIRST_TARGET_IP" -s "$NVMF_PORT" diff --git a/test/nvmf/host/aer.sh b/test/nvmf/host/aer.sh index 45876cb43..19940e3ad 100755 --- a/test/nvmf/host/aer.sh +++ b/test/nvmf/host/aer.sh @@ -28,7 +28,7 @@ waitforlisten $nvmfpid ${RPC_PORT} timing_exit start_nvmf_tgt bdevs="$bdevs $($rpc_py construct_malloc_bdev 64 512)" -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" $rootdir/test/lib/nvme/aer/aer -r "\ trtype:RDMA \ diff --git a/test/nvmf/host/fio.sh b/test/nvmf/host/fio.sh index 9a02fa2f8..7deaa1370 100755 --- a/test/nvmf/host/fio.sh +++ b/test/nvmf/host/fio.sh @@ -33,7 +33,7 @@ waitforlisten $nvmfpid ${RPC_PORT} timing_exit start_nvmf_tgt bdevs="$bdevs $($rpc_py construct_malloc_bdev 64 512)" -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" PLUGIN_DIR=$rootdir/examples/nvme/fio_plugin diff --git a/test/nvmf/host/identify.sh b/test/nvmf/host/identify.sh index 73a3434e4..e459053e1 100755 --- a/test/nvmf/host/identify.sh +++ b/test/nvmf/host/identify.sh @@ -31,7 +31,7 @@ timing_exit start_nvmf_tgt bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)" -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" $rootdir/examples/nvme/identify/identify -r "\ trtype:RDMA \ diff --git a/test/nvmf/host/perf.sh b/test/nvmf/host/perf.sh index 14ce5a3fb..b2d0e025c 100755 --- a/test/nvmf/host/perf.sh +++ b/test/nvmf/host/perf.sh @@ -32,7 +32,7 @@ timing_exit start_nvmf_tgt bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)" -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" $rootdir/examples/nvme/perf/perf -q 128 -s 4096 -w randrw -M 50 -t 1 -r "trtype:RDMA adrfam:IPv4 traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" sync diff --git a/test/nvmf/multiconnection/multiconnection.sh b/test/nvmf/multiconnection/multiconnection.sh index 87456bb62..6a194321a 100755 --- a/test/nvmf/multiconnection/multiconnection.sh +++ b/test/nvmf/multiconnection/multiconnection.sh @@ -35,7 +35,7 @@ modprobe -v nvme-rdma for i in `seq 1 11` do bdevs="$($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)" - $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode${i} "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT" '' -s SPDK${i} -n "$bdevs" + $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode${i} "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT" '' -a -s SPDK${i} -n "$bdevs" done for i in `seq 1 11`; do diff --git a/test/nvmf/nvme_cli/nvme_cli.sh b/test/nvmf/nvme_cli/nvme_cli.sh index 733f161d5..434fcd9e5 100755 --- a/test/nvmf/nvme_cli/nvme_cli.sh +++ b/test/nvmf/nvme_cli/nvme_cli.sh @@ -34,7 +34,7 @@ bdevs="$bdevs $($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SI modprobe -v nvme-rdma -$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" +$rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode1 "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" nvme connect -t rdma -n "nqn.2016-06.io.spdk:cnode1" -a "$NVMF_FIRST_TARGET_IP" -s "$NVMF_PORT" diff --git a/test/nvmf/rpc/rpc.sh b/test/nvmf/rpc/rpc.sh index 66c2233d6..9b62ee295 100755 --- a/test/nvmf/rpc/rpc.sh +++ b/test/nvmf/rpc/rpc.sh @@ -45,7 +45,7 @@ do j=0 for bdf in $bdfs; do let j=j+1 - $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode$j "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -s SPDK00000000000001 -n "$bdevs" + $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode$j "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:4420" '' -a -s SPDK00000000000001 -n "$bdevs" done n=$j diff --git a/test/nvmf/shutdown/shutdown.sh b/test/nvmf/shutdown/shutdown.sh index 3c9095c83..aef53b166 100755 --- a/test/nvmf/shutdown/shutdown.sh +++ b/test/nvmf/shutdown/shutdown.sh @@ -34,7 +34,7 @@ timing_exit start_nvmf_tgt for i in `seq 1 10` do bdevs="$($rpc_py construct_malloc_bdev $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE)" - $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode${i} "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT" '' -s SPDK${i} -n "$bdevs" + $rpc_py construct_nvmf_subsystem nqn.2016-06.io.spdk:cnode${i} "trtype:RDMA traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT" '' -a -s SPDK${i} -n "$bdevs" done # Kill nvmf tgt without removing any subsystem to check whether it can shutdown correctly