From f8433aad23d855497fb63e012b1f127f532b30dc Mon Sep 17 00:00:00 2001 From: Seth Howell Date: Fri, 16 Aug 2019 08:53:48 -0700 Subject: [PATCH] rpc/nvmf: add tgt_name options to relevant RPCs. All of the RPCs in lib/nvmf/nvmf_rpc.c rely on knowing which nvmf_tgt they should work with. They have historically relied on the assumption that there will only be a single target in a given application. This is true for the example application in the spdk repo, but it is not necessarily true generally, By adding an option tgt_name parameter to the RPCs we enable them for multi-target NVMe-oF applications. We also further reduce the coupling between the library and the example application. Change-Id: I03b6695da05a42af3024842ed87d2ce2c296f33f Signed-off-by: Seth Howell Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/465442 Tested-by: SPDK CI Jenkins Reviewed-by: Broadcom SPDK FC-NVMe CI Reviewed-by: Ben Walker Reviewed-by: Jim Harris Reviewed-by: Paul Luse --- CHANGELOG.md | 3 + doc/jsonrpc.md | 21 ++++++- lib/nvmf/nvmf_rpc.c | 137 +++++++++++++++++++++++++++++++++----------- scripts/rpc.py | 39 ++++++++++--- scripts/rpc/nvmf.py | 101 +++++++++++++++++++++++++++----- 5 files changed, 244 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 326d87088..3bfdc966d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ retrieve a pointer to an `spdk_nvmf_tgt` object by supplying its name. In the sp case where an RPC or application only creates a single target, this function can accept a null name parameter and will return the only available target. +The majority of the NVMe-oF RPCs now accept an optional tgt_name parameter. This will +allow those RPCs to work with applications that create more than one target. + ### nvme Added `no_shn_notification` to NVMe controller initialization options, users can enable diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 0cd1f02e9..0d5b35ddf 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -3648,6 +3648,7 @@ Initialize an NVMe-oF transport with the given options. Name | Optional | Type | Description --------------------------- | -------- | --------| ----------- trtype | Required | string | Transport type (ex. RDMA) +tgt_name | Optional | string | Parent NVMe-oF target name. max_queue_depth | Optional | number | Max number of outstanding I/O per queue max_qpairs_per_ctrlr | Optional | number | Max number of SQ and CQ per controller in_capsule_data_size | Optional | number | Max number of in-capsule data size @@ -3692,7 +3693,9 @@ Example response: ### Parameters -This method has no parameters. +Name | Optional | Type | Description +--------------------------- | -------- | ------------| ----------- +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -3755,6 +3758,7 @@ Construct an NVMe over Fabrics target subsystem. Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN +tgt_name | Optional | string | Parent NVMe-oF target name. serial_number | Optional | string | Serial number of virtual controller model_number | Optional | string | Model number of virtual controller max_namespaces | Optional | number | Maximum number of namespaces that can be attached to the subsystem. Default: 0 (Unlimited) @@ -3797,6 +3801,7 @@ Delete an existing NVMe-oF subsystem. Parameter | Optional | Type | Description ---------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN to delete. +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -3832,6 +3837,7 @@ Add a new listen address to an NVMe-oF subsystem. Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN +tgt_name | Optional | string | Parent NVMe-oF target name. listen_address | Required | object | @ref rpc_nvmf_listen_address object ### listen_address {#rpc_nvmf_listen_address} @@ -3884,6 +3890,7 @@ Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN namespace | Required | object | @ref rpc_nvmf_namespace object +tgt_name | Optional | string | Parent NVMe-oF target name. ### namespace {#rpc_nvmf_namespace} @@ -3936,6 +3943,7 @@ Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN nsid | Required | number | Namespace ID +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -3973,6 +3981,7 @@ Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN host | Required | string | Host NQN to add to the list of allowed host NQNs +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -4010,6 +4019,7 @@ Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN host | Required | string | Host NQN to remove from the list of allowed host NQNs +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -4047,6 +4057,7 @@ Name | Optional | Type | Description ----------------------- | -------- | ----------- | ----------- nqn | Required | string | Subsystem NQN allow_any_host | Required | boolean | Allow any host (`true`) or enforce allowed host whitelist (`false`). +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -4150,7 +4161,9 @@ Example response: ### Parameters -This method has no parameters. +Name | Optional | Type | Description +--------------------------- | -------- | ------------| ----------- +tgt_name | Optional | string | Parent NVMe-oF target name. ### Example @@ -4189,7 +4202,9 @@ Retrieve current statistics of the NVMf subsystem. ### Parameters -This method has no parameters. +Name | Optional | Type | Description +--------------------------- | -------- | ------------| ----------- +tgt_name | Optional | string | Parent NVMe-oF target name. ### Response diff --git a/lib/nvmf/nvmf_rpc.c b/lib/nvmf/nvmf_rpc.c index 63e2fbe05..934550a9b 100644 --- a/lib/nvmf/nvmf_rpc.c +++ b/lib/nvmf/nvmf_rpc.c @@ -182,6 +182,14 @@ decode_ns_uuid(const struct spdk_json_val *val, void *out) return rc; } +struct rpc_get_subsystem { + char *tgt_name; +}; + +static const struct spdk_json_object_decoder rpc_get_subsystem_decoders[] = { + {"tgt_name", offsetof(struct rpc_get_subsystem, tgt_name), spdk_json_decode_string, true}, +}; + static void dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem) { @@ -294,20 +302,26 @@ static void spdk_rpc_get_nvmf_subsystems(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) { + struct rpc_get_subsystem req = { 0 }; struct spdk_json_write_ctx *w; struct spdk_nvmf_subsystem *subsystem; struct spdk_nvmf_tgt *tgt; - if (params != NULL) { - spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, - "get_nvmf_subsystems requires no parameters"); - return; + if (params) { + if (spdk_json_decode_object(params, rpc_get_subsystem_decoders, + SPDK_COUNTOF(rpc_get_subsystem_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + return; + } } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(req.tgt_name); if (!tgt) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to find a target."); + free(req.tgt_name); return; } @@ -320,6 +334,7 @@ spdk_rpc_get_nvmf_subsystems(struct spdk_jsonrpc_request *request, } spdk_json_write_array_end(w); spdk_jsonrpc_end_result(request, w); + free(req.tgt_name); } SPDK_RPC_REGISTER("get_nvmf_subsystems", spdk_rpc_get_nvmf_subsystems, SPDK_RPC_RUNTIME) @@ -327,6 +342,7 @@ struct rpc_subsystem_create { char *nqn; char *serial_number; char *model_number; + char *tgt_name; uint32_t max_namespaces; bool allow_any_host; }; @@ -335,6 +351,7 @@ static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = { {"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string}, {"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true}, {"model_number", offsetof(struct rpc_subsystem_create, model_number), spdk_json_decode_string, true}, + {"tgt_name", offsetof(struct rpc_subsystem_create, tgt_name), spdk_json_decode_string, true}, {"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true}, {"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true}, }; @@ -371,7 +388,7 @@ spdk_rpc_nvmf_subsystem_create(struct spdk_jsonrpc_request *request, goto invalid; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(req->tgt_name); if (!tgt) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to find a target."); @@ -401,6 +418,7 @@ spdk_rpc_nvmf_subsystem_create(struct spdk_jsonrpc_request *request, spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host); free(req->nqn); + free(req->tgt_name); free(req->serial_number); free(req->model_number); free(req); @@ -416,6 +434,7 @@ invalid: invalid_custom_response: if (req) { free(req->nqn); + free(req->tgt_name); free(req->serial_number); free(req->model_number); } @@ -425,12 +444,14 @@ SPDK_RPC_REGISTER("nvmf_subsystem_create", spdk_rpc_nvmf_subsystem_create, SPDK_ struct rpc_delete_subsystem { char *nqn; + char *tgt_name; }; static void free_rpc_delete_subsystem(struct rpc_delete_subsystem *r) { free(r->nqn); + free(r->tgt_name); } static void @@ -449,13 +470,14 @@ spdk_rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem, static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = { {"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string}, + {"tgt_name", offsetof(struct rpc_delete_subsystem, tgt_name), spdk_json_decode_string, true}, }; static void spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) { - struct rpc_delete_subsystem req = {}; + struct rpc_delete_subsystem req = { 0 }; struct spdk_nvmf_subsystem *subsystem; struct spdk_nvmf_tgt *tgt; @@ -471,7 +493,7 @@ spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_request *request, goto invalid; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(req.tgt_name); if (!tgt) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to find a target."); @@ -551,6 +573,7 @@ enum nvmf_rpc_listen_op { struct nvmf_rpc_listener_ctx { char *nqn; + char *tgt_name; struct spdk_nvmf_tgt *tgt; struct spdk_nvmf_subsystem *subsystem; struct rpc_listen_address address; @@ -564,12 +587,14 @@ struct nvmf_rpc_listener_ctx { static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = { {"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string}, {"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address}, + {"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true}, }; static void nvmf_rpc_listener_ctx_free(struct nvmf_rpc_listener_ctx *ctx) { free(ctx->nqn); + free(ctx->tgt_name); free_rpc_listen_address(&ctx->address); free(ctx); } @@ -719,7 +744,7 @@ spdk_rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -782,7 +807,7 @@ spdk_rpc_nvmf_subsystem_remove_listener(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -857,6 +882,7 @@ decode_rpc_ns_params(const struct spdk_json_val *val, void *out) struct nvmf_rpc_ns_ctx { char *nqn; + char *tgt_name; struct spdk_nvmf_ns_params ns_params; struct spdk_jsonrpc_request *request; @@ -866,12 +892,14 @@ struct nvmf_rpc_ns_ctx { static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ns_decoder[] = { {"nqn", offsetof(struct nvmf_rpc_ns_ctx, nqn), spdk_json_decode_string}, {"namespace", offsetof(struct nvmf_rpc_ns_ctx, ns_params), decode_rpc_ns_params}, + {"tgt_name", offsetof(struct nvmf_rpc_ns_ctx, tgt_name), spdk_json_decode_string, true}, }; static void nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx) { free(ctx->nqn); + free(ctx->tgt_name); free(ctx->ns_params.bdev_name); free(ctx->ns_params.ptpl_file); free(ctx); @@ -972,7 +1000,7 @@ spdk_rpc_nvmf_subsystem_add_ns(struct spdk_jsonrpc_request *request, ctx->request = request; ctx->response_sent = false; - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -999,6 +1027,7 @@ SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", spdk_rpc_nvmf_subsystem_add_ns, SPDK_ struct nvmf_rpc_remove_ns_ctx { char *nqn; + char *tgt_name; uint32_t nsid; struct spdk_jsonrpc_request *request; @@ -1008,12 +1037,14 @@ struct nvmf_rpc_remove_ns_ctx { static const struct spdk_json_object_decoder nvmf_rpc_subsystem_remove_ns_decoder[] = { {"nqn", offsetof(struct nvmf_rpc_remove_ns_ctx, nqn), spdk_json_decode_string}, {"nsid", offsetof(struct nvmf_rpc_remove_ns_ctx, nsid), spdk_json_decode_uint32}, + {"tgt_name", offsetof(struct nvmf_rpc_remove_ns_ctx, tgt_name), spdk_json_decode_string, true}, }; static void nvmf_rpc_remove_ns_ctx_free(struct nvmf_rpc_remove_ns_ctx *ctx) { free(ctx->nqn); + free(ctx->tgt_name); free(ctx); } @@ -1084,7 +1115,7 @@ spdk_rpc_nvmf_subsystem_remove_ns(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1123,6 +1154,7 @@ struct nvmf_rpc_host_ctx { char *nqn; char *host; + char *tgt_name; enum nvmf_rpc_host_op op; @@ -1134,6 +1166,7 @@ struct nvmf_rpc_host_ctx { static const struct spdk_json_object_decoder nvmf_rpc_subsystem_host_decoder[] = { {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, {"host", offsetof(struct nvmf_rpc_host_ctx, host), spdk_json_decode_string}, + {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true}, }; static void @@ -1141,6 +1174,7 @@ nvmf_rpc_host_ctx_free(struct nvmf_rpc_host_ctx *ctx) { free(ctx->nqn); free(ctx->host); + free(ctx->tgt_name); free(ctx); } @@ -1221,7 +1255,7 @@ spdk_rpc_nvmf_subsystem_add_host(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1273,7 +1307,7 @@ spdk_rpc_nvmf_subsystem_remove_host(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1307,6 +1341,7 @@ SPDK_RPC_REGISTER("nvmf_subsystem_remove_host", spdk_rpc_nvmf_subsystem_remove_h static const struct spdk_json_object_decoder nvmf_rpc_subsystem_any_host_decoder[] = { {"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string}, {"allow_any_host", offsetof(struct nvmf_rpc_host_ctx, allow_any_host), spdk_json_decode_bool}, + {"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true}, }; static void @@ -1332,7 +1367,7 @@ spdk_rpc_nvmf_subsystem_allow_any_host(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1364,7 +1399,8 @@ SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", spdk_rpc_nvmf_subsystem_allow struct nvmf_rpc_create_transport_ctx { char *trtype; - struct spdk_nvmf_transport_opts opts; + char *tgt_name; + struct spdk_nvmf_transport_opts opts; struct spdk_jsonrpc_request *request; }; @@ -1422,12 +1458,17 @@ static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] "sock_priority", offsetof(struct nvmf_rpc_create_transport_ctx, opts.sock_priority), spdk_json_decode_uint32, true }, + { + "tgt_name", offsetof(struct nvmf_rpc_create_transport_ctx, tgt_name), + spdk_json_decode_string, true + }, }; static void nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx) { free(ctx->trtype); + free(ctx->tgt_name); free(ctx); } @@ -1479,7 +1520,7 @@ spdk_rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request, return; } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!tgt) { SPDK_ERRLOG("Unable to find a target object.\n"); spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1573,24 +1614,38 @@ dump_nvmf_transport(struct spdk_json_write_ctx *w, struct spdk_nvmf_transport *t spdk_json_write_object_end(w); } +struct rpc_get_transport { + char *tgt_name; +}; + +static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = { + {"tgt_name", offsetof(struct rpc_get_transport, tgt_name), spdk_json_decode_string, true}, +}; + static void spdk_rpc_get_nvmf_transports(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) { + struct rpc_get_transport req = { 0 }; struct spdk_json_write_ctx *w; struct spdk_nvmf_transport *transport; struct spdk_nvmf_tgt *tgt; - if (params != NULL) { - spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, - "get_nvmf_transports requires no parameters"); - return; + if (params) { + if (spdk_json_decode_object(params, rpc_get_transport_decoders, + SPDK_COUNTOF(rpc_get_transport_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + return; + } } - tgt = spdk_nvmf_get_tgt(NULL); + tgt = spdk_nvmf_get_tgt(req.tgt_name); if (!tgt) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to find a target."); + free(req.tgt_name); return; } @@ -1603,15 +1658,28 @@ spdk_rpc_get_nvmf_transports(struct spdk_jsonrpc_request *request, } spdk_json_write_array_end(w); spdk_jsonrpc_end_result(request, w); + free(req.tgt_name); } SPDK_RPC_REGISTER("get_nvmf_transports", spdk_rpc_get_nvmf_transports, SPDK_RPC_RUNTIME) struct rpc_nvmf_get_stats_ctx { + char *tgt_name; struct spdk_nvmf_tgt *tgt; struct spdk_jsonrpc_request *request; struct spdk_json_write_ctx *w; }; +static const struct spdk_json_object_decoder rpc_get_stats_decoders[] = { + {"tgt_name", offsetof(struct rpc_nvmf_get_stats_ctx, tgt_name), spdk_json_decode_string, true}, +}; + +static void +free_get_stats_ctx(struct rpc_nvmf_get_stats_ctx *ctx) +{ + free(ctx->tgt_name); + free(ctx); +} + static void rpc_nvmf_get_stats_done(struct spdk_io_channel_iter *i, int status) { @@ -1620,7 +1688,7 @@ rpc_nvmf_get_stats_done(struct spdk_io_channel_iter *i, int status) spdk_json_write_array_end(ctx->w); spdk_json_write_object_end(ctx->w); spdk_jsonrpc_end_result(ctx->request, ctx->w); - free(ctx); + free_get_stats_ctx(ctx); } static void @@ -1705,12 +1773,6 @@ spdk_rpc_nvmf_get_stats(struct spdk_jsonrpc_request *request, { struct rpc_nvmf_get_stats_ctx *ctx; - if (params) { - spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, - "'nvmf_get_stats' requires no arguments"); - return; - } - ctx = calloc(1, sizeof(*ctx)); if (!ctx) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, @@ -1719,17 +1781,28 @@ spdk_rpc_nvmf_get_stats(struct spdk_jsonrpc_request *request, } ctx->request = request; - ctx->tgt = spdk_nvmf_get_tgt(NULL); + if (params) { + if (spdk_json_decode_object(params, rpc_get_stats_decoders, + SPDK_COUNTOF(rpc_get_stats_decoders), + ctx)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + free_get_stats_ctx(ctx); + return; + } + } + + ctx->tgt = spdk_nvmf_get_tgt(ctx->tgt_name); if (!ctx->tgt) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Unable to find a target."); - free(ctx); + free_get_stats_ctx(ctx); return; } ctx->w = spdk_jsonrpc_begin_result(ctx->request); if (NULL == ctx->w) { - free(ctx); + free_get_stats_ctx(ctx); return; } diff --git a/scripts/rpc.py b/scripts/rpc.py index 6ce8b246b..e76dd22a3 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -1462,6 +1462,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse def nvmf_create_transport(args): rpc.nvmf.nvmf_create_transport(args.client, trtype=args.trtype, + tgt_name=args.tgt_name, max_queue_depth=args.max_queue_depth, max_qpairs_per_ctrlr=args.max_qpairs_per_ctrlr, in_capsule_data_size=args.in_capsule_data_size, @@ -1478,6 +1479,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p = subparsers.add_parser('nvmf_create_transport', help='Create NVMf transport') p.add_argument('-t', '--trtype', help='Transport type (ex. RDMA)', type=str, required=True) + p.add_argument('-g', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.add_argument('-q', '--max-queue-depth', help='Max number of outstanding I/O per queue', type=int) p.add_argument('-p', '--max-qpairs-per-ctrlr', help='Max number of SQ and CQ per controller', type=int) p.add_argument('-c', '--in-capsule-data-size', help='Max number of in-capsule data size', type=int) @@ -1494,22 +1496,25 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.set_defaults(func=nvmf_create_transport) def get_nvmf_transports(args): - print_dict(rpc.nvmf.get_nvmf_transports(args.client)) + print_dict(rpc.nvmf.get_nvmf_transports(args.client, tgt_name=args.tgt_name)) p = subparsers.add_parser('get_nvmf_transports', help='Display nvmf transports') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=get_nvmf_transports) def get_nvmf_subsystems(args): - print_dict(rpc.nvmf.get_nvmf_subsystems(args.client)) + print_dict(rpc.nvmf.get_nvmf_subsystems(args.client, tgt_name=args.tgt_name)) p = subparsers.add_parser('get_nvmf_subsystems', help='Display nvmf subsystems') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=get_nvmf_subsystems) def nvmf_subsystem_create(args): rpc.nvmf.nvmf_subsystem_create(args.client, nqn=args.nqn, + tgt_name=args.tgt_name, serial_number=args.serial_number, model_number=args.model_number, allow_any_host=args.allow_any_host, @@ -1517,6 +1522,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p = subparsers.add_parser('nvmf_subsystem_create', help='Create an NVMe-oF subsystem') p.add_argument('nqn', help='Subsystem NQN (ASCII)') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.add_argument("-s", "--serial-number", help=""" Format: 'sn' etc Example: 'SPDK00000000000001'""", default='00000000000000000000') @@ -1530,12 +1536,14 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse def delete_nvmf_subsystem(args): rpc.nvmf.delete_nvmf_subsystem(args.client, - nqn=args.subsystem_nqn) + nqn=args.subsystem_nqn, + tgt_name=args.tgt_name) 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.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=delete_nvmf_subsystem) def nvmf_subsystem_add_listener(args): @@ -1543,6 +1551,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse nqn=args.nqn, trtype=args.trtype, traddr=args.traddr, + tgt_name=args.tgt_name, adrfam=args.adrfam, trsvcid=args.trsvcid) @@ -1550,6 +1559,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True) p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True) + p.add_argument('-p', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host') p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number') p.set_defaults(func=nvmf_subsystem_add_listener) @@ -1559,6 +1569,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse nqn=args.nqn, trtype=args.trtype, traddr=args.traddr, + tgt_name=args.tgt_name, adrfam=args.adrfam, trsvcid=args.trsvcid) @@ -1566,6 +1577,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma', required=True) p.add_argument('-a', '--traddr', help='NVMe-oF transport address: e.g., an ip address', required=True) + p.add_argument('-p', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.add_argument('-f', '--adrfam', help='NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc, intra_host') p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number') p.set_defaults(func=nvmf_subsystem_remove_listener) @@ -1574,6 +1586,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse rpc.nvmf.nvmf_subsystem_add_ns(args.client, nqn=args.nqn, bdev_name=args.bdev_name, + tgt_name=args.tgt_name, ptpl_file=args.ptpl_file, nsid=args.nsid, nguid=args.nguid, @@ -1583,6 +1596,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p = subparsers.add_parser('nvmf_subsystem_add_ns', help='Add a namespace to an NVMe-oF subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('bdev_name', help='The name of the bdev that will back this namespace') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.add_argument('-p', '--ptpl-file', help='The persistent reservation storage location (optional)', type=str) p.add_argument('-n', '--nsid', help='The requested NSID (optional)', type=int) p.add_argument('-g', '--nguid', help='Namespace globally unique identifier (optional)') @@ -1593,49 +1607,58 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse def nvmf_subsystem_remove_ns(args): rpc.nvmf.nvmf_subsystem_remove_ns(args.client, nqn=args.nqn, - nsid=args.nsid) + nsid=args.nsid, + tgt_name=args.tgt_name) p = subparsers.add_parser('nvmf_subsystem_remove_ns', help='Remove a namespace to an NVMe-oF subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('nsid', help='The requested NSID', type=int) + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_subsystem_remove_ns) def nvmf_subsystem_add_host(args): rpc.nvmf.nvmf_subsystem_add_host(args.client, nqn=args.nqn, - host=args.host) + host=args.host, + tgt_name=args.tgt_name) p = subparsers.add_parser('nvmf_subsystem_add_host', help='Add a host to an NVMe-oF subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('host', help='Host NQN to allow') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_subsystem_add_host) def nvmf_subsystem_remove_host(args): rpc.nvmf.nvmf_subsystem_remove_host(args.client, nqn=args.nqn, - host=args.host) + host=args.host, + tgt_name=args.tgt_name) p = subparsers.add_parser('nvmf_subsystem_remove_host', help='Remove a host from an NVMe-oF subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('host', help='Host NQN to remove') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_subsystem_remove_host) def nvmf_subsystem_allow_any_host(args): rpc.nvmf.nvmf_subsystem_allow_any_host(args.client, nqn=args.nqn, - disable=args.disable) + disable=args.disable, + tgt_name=args.tgt_name) p = subparsers.add_parser('nvmf_subsystem_allow_any_host', help='Allow any host to connect to the subsystem') p.add_argument('nqn', help='NVMe-oF subsystem NQN') p.add_argument('-e', '--enable', action='store_true', help='Enable allowing any host') p.add_argument('-d', '--disable', action='store_true', help='Disable allowing any host') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_subsystem_allow_any_host) def nvmf_get_stats(args): - print_dict(rpc.nvmf.nvmf_get_stats(args.client)) + print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name)) p = subparsers.add_parser( 'nvmf_get_stats', help='Display current statistics for NVMf subsystem') + p.add_argument('-t', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_get_stats) # pmem diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index e0214eeb7..d92a76cb8 100644 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -37,6 +37,7 @@ def set_nvmf_target_config(client, def nvmf_create_transport(client, trtype, + tgt_name=None, max_queue_depth=None, max_qpairs_per_ctrlr=None, in_capsule_data_size=None, @@ -73,6 +74,8 @@ def nvmf_create_transport(client, params = {} params['trtype'] = trtype + if tgt_name: + params['tgt_name'] = tgt_name if max_queue_depth: params['max_queue_depth'] = max_queue_depth if max_qpairs_per_ctrlr: @@ -102,27 +105,48 @@ def nvmf_create_transport(client, return client.call('nvmf_create_transport', params) -def get_nvmf_transports(client): +def get_nvmf_transports(client, tgt_name=None): """Get list of NVMe-oF transports. + Args: + tgt_name: name of the parent NVMe-oF target (optional). Returns: List of NVMe-oF transport objects. """ - return client.call('get_nvmf_transports') + + params = {} + + if tgt_name: + params = { + 'tgt_name': tgt_name, + } + + return client.call('get_nvmf_transports', params) -def get_nvmf_subsystems(client): +def get_nvmf_subsystems(client, tgt_name=None): """Get list of NVMe-oF subsystems. + Args: + tgt_name: name of the parent NVMe-oF target (optional). Returns: List of NVMe-oF subsystem objects. """ - return client.call('get_nvmf_subsystems') + + params = {} + + if tgt_name: + params = { + 'tgt_name': tgt_name, + } + + return client.call('get_nvmf_subsystems', params) def nvmf_subsystem_create(client, nqn, serial_number, + tgt_name=None, model_number='SPDK bdev Controller', allow_any_host=False, max_namespaces=0): @@ -130,6 +154,7 @@ def nvmf_subsystem_create(client, Args: nqn: Subsystem NQN. + tgt_name: name of the parent NVMe-oF target (optional). serial_number: Serial number of virtual controller. model_number: Model number of virtual controller. allow_any_host: Allow any host (True) or enforce allowed host whitelist (False). Default: False. @@ -154,10 +179,13 @@ def nvmf_subsystem_create(client, if max_namespaces: params['max_namespaces'] = max_namespaces + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_create', params) -def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam): +def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam, tgt_name=None): """Add a new listen address to an NVMe-oF subsystem. Args: @@ -165,6 +193,7 @@ def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam): trtype: Transport type ("RDMA"). traddr: Transport address. trsvcid: Transport service ID. + tgt_name: name of the parent NVMe-oF target (optional). adrfam: Address family ("IPv4", "IPv6", "IB", or "FC"). Returns: @@ -180,6 +209,9 @@ def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam): params = {'nqn': nqn, 'listen_address': listen_address} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_add_listener', params) @@ -189,7 +221,8 @@ def nvmf_subsystem_remove_listener( trtype, traddr, trsvcid, - adrfam): + adrfam, + tgt_name=None): """Remove existing listen address from an NVMe-oF subsystem. Args: @@ -197,6 +230,7 @@ def nvmf_subsystem_remove_listener( trtype: Transport type ("RDMA"). traddr: Transport address. trsvcid: Transport service ID. + tgt_name: name of the parent NVMe-oF target (optional). adrfam: Address family ("IPv4", "IPv6", "IB", or "FC"). Returns: @@ -212,15 +246,19 @@ def nvmf_subsystem_remove_listener( params = {'nqn': nqn, 'listen_address': listen_address} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_remove_listener', params) -def nvmf_subsystem_add_ns(client, nqn, bdev_name, ptpl_file=None, nsid=None, nguid=None, eui64=None, uuid=None): +def nvmf_subsystem_add_ns(client, nqn, bdev_name, tgt_name=None, ptpl_file=None, nsid=None, nguid=None, eui64=None, uuid=None): """Add a namespace to a subsystem. Args: nqn: Subsystem NQN. bdev_name: Name of bdev to expose as a namespace. + tgt_name: name of the parent NVMe-oF target (optional). nsid: Namespace ID (optional). nguid: 16-byte namespace globally unique identifier in hexadecimal (optional). eui64: 8-byte namespace EUI-64 in hexadecimal (e.g. "ABCDEF0123456789") (optional). @@ -249,15 +287,19 @@ def nvmf_subsystem_add_ns(client, nqn, bdev_name, ptpl_file=None, nsid=None, ngu params = {'nqn': nqn, 'namespace': ns} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_add_ns', params) -def nvmf_subsystem_remove_ns(client, nqn, nsid): +def nvmf_subsystem_remove_ns(client, nqn, nsid, tgt_name=None): """Remove a existing namespace from a subsystem. Args: nqn: Subsystem NQN. nsid: Namespace ID. + tgt_name: name of the parent NVMe-oF target (optional). Returns: True or False @@ -265,15 +307,19 @@ def nvmf_subsystem_remove_ns(client, nqn, nsid): params = {'nqn': nqn, 'nsid': nsid} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_remove_ns', params) -def nvmf_subsystem_add_host(client, nqn, host): +def nvmf_subsystem_add_host(client, nqn, host, tgt_name=None): """Add a host NQN to the whitelist of allowed hosts. Args: nqn: Subsystem NQN. host: Host NQN to add to the list of allowed host NQNs + tgt_name: name of the parent NVMe-oF target (optional). Returns: True or False @@ -281,15 +327,19 @@ def nvmf_subsystem_add_host(client, nqn, host): params = {'nqn': nqn, 'host': host} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_add_host', params) -def nvmf_subsystem_remove_host(client, nqn, host): +def nvmf_subsystem_remove_host(client, nqn, host, tgt_name=None): """Remove a host NQN from the whitelist of allowed hosts. Args: nqn: Subsystem NQN. host: Host NQN to remove to the list of allowed host NQNs + tgt_name: name of the parent NVMe-oF target (optional). Returns: True or False @@ -297,41 +347,64 @@ def nvmf_subsystem_remove_host(client, nqn, host): params = {'nqn': nqn, 'host': host} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_remove_host', params) -def nvmf_subsystem_allow_any_host(client, nqn, disable): +def nvmf_subsystem_allow_any_host(client, nqn, disable, tgt_name=None): """Configure a subsystem to allow any host to connect or to enforce the host NQN whitelist. Args: nqn: Subsystem NQN. disable: Allow any host (true) or enforce allowed host whitelist (false). + tgt_name: name of the parent NVMe-oF target (optional). Returns: True or False """ params = {'nqn': nqn, 'allow_any_host': False if disable else True} + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('nvmf_subsystem_allow_any_host', params) -def delete_nvmf_subsystem(client, nqn): +def delete_nvmf_subsystem(client, nqn, tgt_name=None): """Delete an existing NVMe-oF subsystem. Args: nqn: Subsystem NQN. + tgt_name: name of the parent NVMe-oF target (optional). Returns: True or False """ params = {'nqn': nqn} + + if tgt_name: + params['tgt_name'] = tgt_name + return client.call('delete_nvmf_subsystem', params) -def nvmf_get_stats(client): +def nvmf_get_stats(client, tgt_name=None): """Query NVMf statistics. + Args: + tgt_name: name of the parent NVMe-oF target (optional). + Returns: Current NVMf statistics. """ - return client.call('nvmf_get_stats') + + params = {} + + if tgt_name: + params = { + 'tgt_name': tgt_name, + } + + return client.call('nvmf_get_stats', params)