nvmf: Add support for RPC interfaces.

Change-Id: I6f0fe35bf2876df181ad11294b62d64d97dcac2c
Signed-off-by: Cunyin Chang <cunyin.chang@intel.com>
This commit is contained in:
Cunyin Chang 2016-09-13 10:52:21 +08:00 committed by Jim Harris
parent 1be062decd
commit d20b90b21e
8 changed files with 657 additions and 4 deletions

View File

@ -43,7 +43,7 @@ CFLAGS += $(DPDK_INC)
# TODO: remove this once NVMf has a public API header
CFLAGS += -I$(SPDK_ROOT_DIR)/lib
C_SRCS := conf.c nvmf_tgt.c
C_SRCS := conf.c nvmf_tgt.c nvmf_rpc.c
SPDK_LIBS = \
$(SPDK_ROOT_DIR)/lib/nvmf/libspdk_nvmf.a \

View File

@ -310,7 +310,7 @@ attach_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr *ctr
SPDK_NOTICELOG("Attaching NVMe device %x:%x:%x.%x to subsystem %s\n",
found_domain, found_bus, found_dev, found_func, ctx->subsystem->subnqn);
rc = nvmf_subsystem_add_ctrlr(ctx->subsystem, ctrlr);
rc = nvmf_subsystem_add_ctrlr(ctx->subsystem, ctrlr, dev);
if (rc < 0) {
SPDK_ERRLOG("Failed to add controller to subsystem\n");
}
@ -566,3 +566,156 @@ spdk_nvmf_parse_conf(void)
return 0;
}
int
spdk_nvmf_parse_subsystem_for_rpc(const char *name,
const char *mode, uint32_t lcore,
int num_listen_addresses, struct rpc_listen_address *addresses,
int num_hosts, char *hosts[], const char *bdf,
const char *sn, int num_devs, char *dev_list[])
{
struct spdk_nvmf_subsystem *subsystem;
struct nvmf_tgt_subsystem *app_subsys;
int i, ret;
uint64_t mask;
int num = 0;
if (name == NULL) {
SPDK_ERRLOG("No NQN specified for Subsystem %d\n", num);
return -1;
}
if (num_listen_addresses > MAX_LISTEN_ADDRESSES) {
SPDK_ERRLOG("invalid listen adresses number\n");
return -1;
}
if (num_hosts > MAX_HOSTS) {
SPDK_ERRLOG("invalid hosts number\n");
return -1;
}
app_subsys = nvmf_tgt_subsystem_first();
while (app_subsys) {
if (num < app_subsys->subsystem->num) {
num = app_subsys->subsystem->num + 1;
}
app_subsys = nvmf_tgt_subsystem_next(app_subsys);
}
/* Determine which core to assign to the subsystem */
mask = spdk_app_get_core_mask();
lcore = spdk_nvmf_allocate_lcore(mask, lcore);
app_subsys = nvmf_tgt_create_subsystem(num, name, SPDK_NVMF_SUBTYPE_NVME, lcore);
if (app_subsys == NULL) {
SPDK_ERRLOG("Subsystem creation failed\n");
return -1;
}
subsystem = app_subsys->subsystem;
if (mode == NULL) {
SPDK_ERRLOG("No Mode specified for Subsystem %d\n", num);
return -1;
}
if (strcasecmp(mode, "Direct") == 0) {
subsystem->mode = NVMF_SUBSYSTEM_MODE_DIRECT;
} else if (strcasecmp(mode, "Virtual") == 0) {
subsystem->mode = NVMF_SUBSYSTEM_MODE_VIRTUAL;
} else {
SPDK_ERRLOG("Invalid Subsystem mode: %s\n", mode);
return -1;
}
/* Parse Listen sections */
for (i = 0; i < num_listen_addresses; i++) {
const struct spdk_nvmf_transport *transport;
transport = spdk_nvmf_transport_get(addresses[i].transport);
if (transport == NULL) {
SPDK_ERRLOG("Unknown transport type '%s'\n", addresses[i].transport);
return -1;
}
spdk_nvmf_subsystem_add_listener(subsystem, transport, addresses[i].traddr, addresses[i].trsvcid);
}
/* Parse Host sections */
for (i = 0; i < num_hosts; i++) {
char *host_nqn;
host_nqn = hosts[i];
if (strcmp(host_nqn, "All") == 0)
break;
spdk_nvmf_subsystem_add_host(subsystem, host_nqn);
}
if (subsystem->mode == NVMF_SUBSYSTEM_MODE_DIRECT) {
struct spdk_nvmf_probe_ctx ctx = { 0 };
if (bdf == NULL) {
SPDK_ERRLOG("Subsystem %d: missing NVMe directive\n", num);
return -1;
}
ctx.subsystem = subsystem;
ctx.found = false;
if (strcmp(bdf, "*") == 0) {
ctx.any = true;
} else {
ret = sscanf(bdf, "%x:%x:%x.%x", &ctx.domain, &ctx.bus, &ctx.device, &ctx.function);
if (ret != 4) {
SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", bdf);
return -1;
}
ctx.any = false;
}
if (spdk_nvme_probe(&ctx, probe_cb, attach_cb, NULL)) {
SPDK_ERRLOG("One or more controllers failed in spdk_nvme_probe()\n");
}
} else {
struct spdk_bdev *bdev;
const char *namespace;
if (sn == NULL) {
SPDK_ERRLOG("Subsystem %d: missing serial number\n", num);
return -1;
}
if (spdk_nvmf_validate_sn(sn) != 0) {
return -1;
}
if (num_devs > MAX_VIRTUAL_NAMESPACE) {
return -1;
}
subsystem->dev.virtual.ns_count = 0;
snprintf(subsystem->dev.virtual.sn, MAX_SN_LEN, "%s", sn);
subsystem->ops = &spdk_nvmf_virtual_ctrlr_ops;
for (i = 0; i < num_devs; i++) {
namespace = dev_list[i];
if (!namespace) {
SPDK_ERRLOG("Namespace %d: missing block device\n", i);
return -1;
}
bdev = spdk_bdev_get_by_name(namespace);
if (spdk_nvmf_subsystem_add_ns(subsystem, bdev)) {
return -1;
}
SPDK_NOTICELOG("Attaching block device %s to subsystem %s\n",
bdev->name, subsystem->subnqn);
}
}
ret = spdk_nvmf_acceptor_init();
if (ret < 0) {
SPDK_ERRLOG("spdk_nvmf_acceptor_start() failed\n");
return -1;
}
return 0;
}

390
app/nvmf_tgt/nvmf_rpc.c Normal file
View File

@ -0,0 +1,390 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <pciaccess.h>
#include "nvmf_tgt.h"
#include "nvmf/subsystem.h"
#include "nvmf/transport.h"
#include "spdk/log.h"
#include "spdk/rpc.h"
#include "spdk/pci.h"
#include "spdk/nvme.h"
static void
dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem)
{
struct spdk_nvmf_listen_addr *listen_addr;
struct spdk_nvmf_host *host;
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "core");
spdk_json_write_int32(w, subsystem->lcore);
spdk_json_write_name(w, "nqn");
spdk_json_write_string(w, subsystem->subnqn);
if (subsystem->subtype == SPDK_NVMF_SUBTYPE_NVME) {
spdk_json_write_name(w, "mode");
if (subsystem->mode == NVMF_SUBSYSTEM_MODE_DIRECT) {
spdk_json_write_string(w, "direct");
} else {
spdk_json_write_string(w, "virtual");
}
}
spdk_json_write_name(w, "subtype");
if (subsystem->subtype == SPDK_NVMF_SUBTYPE_NVME) {
spdk_json_write_string(w, "NVMe");
} else {
spdk_json_write_string(w, "Discovery");
}
spdk_json_write_name(w, "listen_addrs");
spdk_json_write_array_begin(w);
TAILQ_FOREACH(listen_addr, &subsystem->listen_addrs, link) {
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "transport");
spdk_json_write_string(w, listen_addr->transport->name);
spdk_json_write_name(w, "traddr");
spdk_json_write_string(w, listen_addr->traddr);
spdk_json_write_name(w, "trsvcid");
spdk_json_write_string(w, listen_addr->trsvcid);
spdk_json_write_object_end(w);
}
spdk_json_write_array_end(w);
spdk_json_write_name(w, "hosts");
spdk_json_write_array_begin(w);
TAILQ_FOREACH(host, &subsystem->hosts, link) {
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "nqn");
spdk_json_write_string(w, host->nqn);
spdk_json_write_object_end(w);
}
spdk_json_write_array_end(w);
if (subsystem->subtype == SPDK_NVMF_SUBTYPE_NVME) {
if (subsystem->mode == NVMF_SUBSYSTEM_MODE_DIRECT) {
struct spdk_pci_device *dev = subsystem->dev.direct.pci_dev;
uint16_t found_domain = spdk_pci_device_get_domain(dev);
uint8_t found_bus = spdk_pci_device_get_bus(dev);
uint8_t found_dev = spdk_pci_device_get_dev(dev);
uint8_t found_func = spdk_pci_device_get_func(dev);
spdk_json_write_name(w, "pci_address");
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "domain");
spdk_json_write_int32(w, found_domain);
spdk_json_write_name(w, "bus");
spdk_json_write_int32(w, found_bus);
spdk_json_write_name(w, "device");
spdk_json_write_int32(w, found_dev);
spdk_json_write_name(w, "function");
spdk_json_write_int32(w, found_func);
spdk_json_write_object_end(w);
} else {
int i;
spdk_json_write_name(w, "serial_number");
spdk_json_write_string(w, subsystem->dev.virtual.sn);
spdk_json_write_name(w, "namespaces");
spdk_json_write_array_begin(w);
for (i = 0; i < subsystem->dev.virtual.ns_count; i++) {
spdk_json_write_object_begin(w);
spdk_json_write_name(w, "nsid");
spdk_json_write_int32(w, i + 1);
spdk_json_write_name(w, "name");
spdk_json_write_string(w, subsystem->dev.virtual.ns_list[i]->name);
spdk_json_write_object_end(w);
}
spdk_json_write_array_end(w);
}
}
spdk_json_write_object_end(w);
}
static void
spdk_rpc_get_nvmf_subsystems(struct spdk_jsonrpc_server_conn *conn,
const struct spdk_json_val *params,
const struct spdk_json_val *id)
{
struct spdk_json_write_ctx *w;
struct nvmf_tgt_subsystem *tgt_subsystem;
if (params != NULL) {
spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"get_nvmf_subsystems requires no parameters");
return;
}
if (id == NULL) {
return;
}
w = spdk_jsonrpc_begin_result(conn, id);
spdk_json_write_array_begin(w);
tgt_subsystem = nvmf_tgt_subsystem_first();
while (tgt_subsystem) {
dump_nvmf_subsystem(w, tgt_subsystem->subsystem);
tgt_subsystem = nvmf_tgt_subsystem_next(tgt_subsystem);
}
spdk_json_write_array_end(w);
spdk_jsonrpc_end_result(conn, w);
}
SPDK_RPC_REGISTER("get_nvmf_subsystems", spdk_rpc_get_nvmf_subsystems)
#define RPC_MAX_LISTEN_ADDRESSES 255
#define RPC_MAX_HOSTS 255
struct rpc_listen_addresses {
size_t num_listen_address;
struct rpc_listen_address addresses[RPC_MAX_LISTEN_ADDRESSES];
};
static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
{"transport", offsetof(struct rpc_listen_address, transport), spdk_json_decode_string},
{"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
{"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string},
};
static int
decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_address *req = (struct rpc_listen_address *)out;
if (spdk_json_decode_object(val, rpc_listen_address_decoders,
sizeof(rpc_listen_address_decoders) / sizeof(*rpc_listen_address_decoders),
req)) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
return -1;
}
return 0;
}
static int
decode_rpc_listen_addresses(const struct spdk_json_val *val, void *out)
{
struct rpc_listen_addresses *listen_addresses = out;
return spdk_json_decode_array(val, decode_rpc_listen_address, &listen_addresses->addresses,
RPC_MAX_LISTEN_ADDRESSES,
&listen_addresses->num_listen_address, sizeof(struct rpc_listen_address));
}
struct rpc_hosts {
size_t num_hosts;
char *hosts[RPC_MAX_HOSTS];
};
static int
decode_rpc_hosts(const struct spdk_json_val *val, void *out)
{
struct rpc_hosts *rpc_hosts = out;
return spdk_json_decode_array(val, spdk_json_decode_string, rpc_hosts->hosts, RPC_MAX_HOSTS,
&rpc_hosts->num_hosts, sizeof(char *));
}
struct rpc_dev_names {
size_t num_names;
char *names[MAX_VIRTUAL_NAMESPACE];
};
static int
decode_rpc_dev_names(const struct spdk_json_val *val, void *out)
{
struct rpc_dev_names *dev_names = out;
return spdk_json_decode_array(val, spdk_json_decode_string, dev_names->names,
MAX_VIRTUAL_NAMESPACE,
&dev_names->num_names, sizeof(char *));
}
static void
free_rpc_dev_names(struct rpc_dev_names *r)
{
size_t i;
for (i = 0; i < r->num_names; i++) {
free(r->names[i]);
}
}
static void
free_rpc_listen_addresses(struct rpc_listen_addresses *r)
{
size_t i;
for (i = 0; i < r->num_listen_address; i++) {
free(r->addresses[i].transport);
free(r->addresses[i].traddr);
free(r->addresses[i].trsvcid);
}
}
static void
free_rpc_hosts(struct rpc_hosts *r)
{
size_t i;
for (i = 0; i < r->num_hosts; i++) {
free(r->hosts[i]);
}
}
struct rpc_subsystem {
int32_t core;
char *mode;
char *nqn;
struct rpc_listen_addresses listen_addresses;
struct rpc_hosts hosts;
char *pci_address;
char *serial_number;
struct rpc_dev_names namespaces;
};
static void
free_rpc_subsystem(struct rpc_subsystem *req)
{
free_rpc_dev_names(&req->namespaces);
free_rpc_listen_addresses(&req->listen_addresses);
free_rpc_hosts(&req->hosts);
}
static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = {
{"core", offsetof(struct rpc_subsystem, core), spdk_json_decode_int32, true},
{"mode", offsetof(struct rpc_subsystem, mode), spdk_json_decode_string},
{"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},
{"pci_address", offsetof(struct rpc_subsystem, pci_address), spdk_json_decode_string, 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},
};
static void
spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_server_conn *conn,
const struct spdk_json_val *params,
const struct spdk_json_val *id)
{
struct rpc_subsystem req = {};
struct spdk_json_write_ctx *w;
int ret;
if (spdk_json_decode_object(params, rpc_subsystem_decoders,
sizeof(rpc_subsystem_decoders) / sizeof(*rpc_subsystem_decoders),
&req)) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
goto invalid;
}
ret = spdk_nvmf_parse_subsystem_for_rpc(req.nqn, req.mode, req.core,
req.listen_addresses.num_listen_address,
req.listen_addresses.addresses,
req.hosts.num_hosts, req.hosts.hosts, req.pci_address,
req.serial_number,
req.namespaces.num_names, req.namespaces.names);
if (ret) {
goto invalid;
}
free_rpc_subsystem(&req);
w = spdk_jsonrpc_begin_result(conn, id);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(conn, w);
return;
invalid:
spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
free_rpc_subsystem(&req);
}
SPDK_RPC_REGISTER("construct_nvmf_subsystem", spdk_rpc_construct_nvmf_subsystem)
struct rpc_delete_subsystem {
char *nqn;
};
static void
free_rpc_delete_subsystem(struct rpc_delete_subsystem *r)
{
free(r->nqn);
}
static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = {
{"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string},
};
static void
spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_server_conn *conn,
const struct spdk_json_val *params,
const struct spdk_json_val *id)
{
struct rpc_delete_subsystem req = {};
struct spdk_json_write_ctx *w;
if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders,
sizeof(rpc_delete_subsystem_decoders) / sizeof(*rpc_delete_subsystem_decoders),
&req)) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
goto invalid;
}
if (req.nqn == NULL) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "missing name param\n");
goto invalid;
}
if (nvmf_tgt_shutdown_subsystem_by_nqn(req.nqn)) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "shutdown_subsystem failed\n");
goto invalid;
}
free_rpc_delete_subsystem(&req);
if (id == NULL) {
return;
}
w = spdk_jsonrpc_begin_result(conn, id);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(conn, w);
return;
invalid:
spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
free_rpc_delete_subsystem(&req);
}
SPDK_RPC_REGISTER("delete_nvmf_subsystem", spdk_rpc_delete_nvmf_subsystem)

View File

@ -266,6 +266,33 @@ nvmf_tgt_delete_subsystems(void)
}
}
struct nvmf_tgt_subsystem *
nvmf_tgt_subsystem_first(void)
{
return TAILQ_FIRST(&g_subsystems);
}
struct nvmf_tgt_subsystem *
nvmf_tgt_subsystem_next(struct nvmf_tgt_subsystem *subsystem)
{
return TAILQ_NEXT(subsystem, tailq);
}
int
nvmf_tgt_shutdown_subsystem_by_nqn(const char *nqn)
{
struct nvmf_tgt_subsystem *tgt_subsystem, *subsys_tmp;
TAILQ_FOREACH_SAFE(tgt_subsystem, &g_subsystems, tailq, subsys_tmp) {
if (strcmp(tgt_subsystem->subsystem->subnqn, nqn) == 0) {
TAILQ_REMOVE(&g_subsystems, tgt_subsystem, tailq);
nvmf_tgt_delete_subsystem(tgt_subsystem);
return 0;
}
}
return -1;
}
static void
usage(void)
{

View File

@ -39,6 +39,12 @@
#include "spdk/nvmf_spec.h"
#include "spdk/queue.h"
struct rpc_listen_address {
char *transport;
char *traddr;
char *trsvcid;
};
struct spdk_nvmf_tgt_conf {
uint32_t acceptor_lcore;
};
@ -54,10 +60,26 @@ struct nvmf_tgt_subsystem {
extern struct spdk_nvmf_tgt_conf g_spdk_nvmf_tgt_conf;
struct nvmf_tgt_subsystem *
nvmf_tgt_subsystem_first(void);
struct nvmf_tgt_subsystem *
nvmf_tgt_subsystem_next(struct nvmf_tgt_subsystem *subsystem);
int spdk_nvmf_parse_conf(void);
struct nvmf_tgt_subsystem *nvmf_tgt_create_subsystem(int num,
const char *name,
enum spdk_nvmf_subtype subtype,
uint32_t lcore);
int
spdk_nvmf_parse_subsystem_for_rpc(const char *name,
const char *mode, uint32_t lcore,
int num_listen_addresses, struct rpc_listen_address *addresses,
int num_hosts, char *hosts[], const char *bdf,
const char *sn, int num_devs, char *dev_list[]);
int
nvmf_tgt_shutdown_subsystem_by_nqn(const char *nqn);
#endif

View File

@ -251,9 +251,10 @@ spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, char *host_n
int
nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
struct spdk_nvme_ctrlr *ctrlr)
struct spdk_nvme_ctrlr *ctrlr, struct spdk_pci_device *dev)
{
subsystem->dev.direct.ctrlr = ctrlr;
subsystem->dev.direct.pci_dev = dev;
/* Assume that all I/O will be handled on one thread for now */
subsystem->dev.direct.io_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, 0);
if (subsystem->dev.direct.io_qpair == NULL) {

View File

@ -112,6 +112,7 @@ struct spdk_nvmf_subsystem {
struct {
struct spdk_nvme_ctrlr *ctrlr;
struct spdk_nvme_qpair *io_qpair;
struct spdk_pci_device *pci_dev;
} direct;
struct {
@ -160,7 +161,7 @@ spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem,
int
nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem,
struct spdk_nvme_ctrlr *ctrlr);
struct spdk_nvme_ctrlr *ctrlr, struct spdk_pci_device *dev);
void
spdk_format_discovery_log(struct spdk_nvmf_discovery_log_page *disc_log, uint32_t length);

View File

@ -302,6 +302,65 @@ def get_interfaces(args):
p = subparsers.add_parser('get_interfaces', help='Display current interface list')
p.set_defaults(func=get_interfaces)
def get_nvmf_subsystems(args):
print_dict(jsonrpc_call('get_nvmf_subsystems'))
p = subparsers.add_parser('get_nvmf_subsystems', help='Display nvmf subsystems')
p.set_defaults(func=get_nvmf_subsystems)
def construct_nvmf_subsystem(args):
namespaces = []
hosts = []
listen_addresses = [dict(u.split(":") for u in a.split(" ")) for a in args.listen.split(",")]
for u in args.hosts.split(" "):
hosts.append(u)
for u in args.namespaces.split(" "):
namespaces.append(u)
params = {
'core': args.core,
'mode': args.mode,
'nqn': args.nqn,
'listen_addresses': listen_addresses,
'hosts': hosts,
'pci_address': args.pci_address,
'serial_number': args.serial_number,
'namespaces': namespaces,
}
jsonrpc_call('construct_nvmf_subsystem', params)
p = subparsers.add_parser('construct_nvmf_subsystem', help='Add a nvmf subsystem')
p.add_argument("-c", "--core", help='The core Nvmf target run on', type=int, default=0)
p.add_argument('mode', help='Target mode: Virtual or Direct')
p.add_argument('nqn', help='Target nqn(ASCII)')
p.add_argument('listen', help="""comma-separated list of Listen <transport:transport_name traddr:address trsvcid:port_id> pairs enclosed
in quotes. Format: 'transport:transport0 traddr:traddr0 trsvcid:trsvcid0,transport:transport1 traddr:traddr1 trsvcid:trsvcid1' etc
Example: 'transport:RDMA traddr:192.168.100.8 trsvcid:4420,transport:RDMA traddr:192.168.100.9 trsvcid:4420'""")
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("-p", "--pci_address", help="""Valid if mode == Direct.
Format: 'domain:device:function' etc
Example: '0000:00:01.0'""", default='0000:00:01.0')
p.add_argument("-s", "--serial_number", help="""Valid if mode == Virtual.
Format: 'sn' etc
Example: 'SPDK00000000000001'""", default='0000:00:01.0')
p.add_argument("-n", "--namespaces", help="""Whitespace-separated list of namespaces.
Format: 'dev1 dev2 dev3' etc
Example: 'Malloc0 Malloc1 Malloc2'
*** The devices must pre-exist ***""", default='Malloc0')
p.set_defaults(func=construct_nvmf_subsystem)
def delete_nvmf_subsystem(args):
params = {'nqn': args.subsystem_nqn}
jsonrpc_call('delete_nvmf_subsystem', params)
p = subparsers.add_parser('delete_nvmf_subsystem', help='Delete a nvmf subsystem')
p.add_argument('subsystem_nqn', help='subsystem nqn to be deleted. Example: nqn.2016-06.io.spdk:cnode1.')
p.set_defaults(func=delete_nvmf_subsystem)
def kill_instance(args):
params = {'sig_name': args.sig_name}