From 6d87bc7a8a81add36396076b855f1341dd764b37 Mon Sep 17 00:00:00 2001 From: Jacek Kalwas Date: Mon, 21 Sep 2020 19:13:08 +0200 Subject: [PATCH] nvmf: allow transport specific options within subsystem Change-Id: Id7b7d5205b468237df4c98715ce8d7bc26145f63 Signed-off-by: Jacek Kalwas Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4246 Community-CI: Broadcom CI Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Aleksey Marchuk --- include/spdk/nvmf_transport.h | 6 +++ lib/nvmf/nvmf_rpc.c | 89 +++++++++++++++++++++++++++++++++++ scripts/rpc.py | 12 +++++ scripts/rpc/nvmf.py | 20 ++++++++ 4 files changed, 127 insertions(+) diff --git a/include/spdk/nvmf_transport.h b/include/spdk/nvmf_transport.h index 6aaae4ce8..fdeb92524 100644 --- a/include/spdk/nvmf_transport.h +++ b/include/spdk/nvmf_transport.h @@ -213,6 +213,12 @@ struct spdk_nvmf_transport_ops { */ void (*opts_init)(struct spdk_nvmf_transport_opts *opts); + /** + * Parse a subsystem opts + */ + int (*subsystem_opts_parse)(struct spdk_nvmf_transport *transport, + const struct spdk_nvmf_subsystem *subsystem, const struct spdk_json_val *opts); + /** * Create a transport for the given transport opts */ diff --git a/lib/nvmf/nvmf_rpc.c b/lib/nvmf/nvmf_rpc.c index 044fa2ad2..7d0400485 100644 --- a/lib/nvmf/nvmf_rpc.c +++ b/lib/nvmf/nvmf_rpc.c @@ -457,6 +457,95 @@ cleanup: SPDK_RPC_REGISTER("nvmf_create_subsystem", rpc_nvmf_create_subsystem, SPDK_RPC_RUNTIME) SPDK_RPC_REGISTER_ALIAS_DEPRECATED(nvmf_create_subsystem, nvmf_subsystem_create) +struct rpc_subsystem_set_options { + char *nqn; + char *tgt_name; + char *trtype; +}; + +static const struct spdk_json_object_decoder rpc_subsystem_set_options_decoders[] = { + {"nqn", offsetof(struct rpc_subsystem_set_options, nqn), spdk_json_decode_string}, + {"tgt_name", offsetof(struct rpc_subsystem_set_options, tgt_name), spdk_json_decode_string, true}, + {"trtype", offsetof(struct rpc_subsystem_set_options, trtype), spdk_json_decode_string}, +}; + +static void +rpc_nvmf_subsystem_set_options(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_subsystem_set_options *req; + struct spdk_nvmf_subsystem *subsystem; + struct spdk_nvmf_transport *transport; + struct spdk_json_write_ctx *w; + struct spdk_nvmf_tgt *tgt; + int rc; + + req = calloc(1, sizeof(*req)); + if (!req) { + SPDK_ERRLOG("Memory allocation failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Memory allocation failed"); + return; + } + + if (spdk_json_decode_object_relaxed(params, rpc_subsystem_set_options_decoders, + SPDK_COUNTOF(rpc_subsystem_set_options_decoders), req)) { + SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + goto cleanup; + } + + tgt = spdk_nvmf_get_tgt(req->tgt_name); + if (!tgt) { + SPDK_ERRLOG("Unable to find target %s\n", req->tgt_name); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Unable to find target %s", req->tgt_name); + goto cleanup; + } + + subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req->nqn); + if (!subsystem) { + SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", req->nqn); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Unable to find subsystem with NQN %s", req->nqn); + goto cleanup; + } + + transport = spdk_nvmf_tgt_get_transport(tgt, req->trtype); + if (!transport) { + SPDK_ERRLOG("Unable to find transport with trtype %s\n", req->trtype); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Unable to find transport with trtype %s", req->trtype); + goto cleanup; + } + + if (!transport->ops->subsystem_opts_parse) { + SPDK_ERRLOG("Unable to find transport ops\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Unable to find transport ops"); + goto cleanup; + } + + rc = transport->ops->subsystem_opts_parse(transport, subsystem, params); + if (rc) { + SPDK_ERRLOG("Unable to parse opts %d\n", rc); + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Unable to parse opts %d", rc); + goto cleanup; + } + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); + +cleanup: + free(req->nqn); + free(req->tgt_name); + free(req->trtype); + free(req); +} +SPDK_RPC_REGISTER("nvmf_subsystem_set_options", rpc_nvmf_subsystem_set_options, SPDK_RPC_RUNTIME) + struct rpc_delete_subsystem { char *nqn; char *tgt_name; diff --git a/scripts/rpc.py b/scripts/rpc.py index 12a55ae7e..590024606 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -1871,6 +1871,18 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument("-r", "--ana-reporting", action='store_true', help="Enable ANA reporting feature") p.set_defaults(func=nvmf_create_subsystem) + def nvmf_subsystem_set_options(args): + rpc.nvmf.nvmf_subsystem_set_options(args.client, + nqn=args.nqn, + trtype=args.trtype, + tgt_name=args.tgt_name) + + p = subparsers.add_parser('nvmf_subsystem_set_options', help='Set a transport specific options for an NVMe-oF subsystem') + p.add_argument('nqn', help='Subsystem NQN (ASCII)') + p.add_argument('-t', '--trtype', help='NVMe-oF transport type: e.g., rdma, tcp, pcie', required=True) + p.add_argument('-g', '--tgt_name', help='The name of the parent NVMe-oF target (optional)', type=str) + p.set_defaults(func=nvmf_subsystem_set_options) + def nvmf_delete_subsystem(args): rpc.nvmf.nvmf_delete_subsystem(args.client, nqn=args.subsystem_nqn, diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index 567ef3c88..ffd090752 100644 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -263,6 +263,26 @@ def nvmf_create_subsystem(client, return client.call('nvmf_create_subsystem', params) +def nvmf_subsystem_set_options(client, nqn, trtype, tgt_name=None): + """Set a transport specific options for an NVMe-oF subsystem. + + Args: + nqn: Subsystem NQN. + trtype: NVMe-oF transport type: e.g., rdma, tcp, pcie. + tgt_name: The name of the parent NVMe-oF target (optional). + + Returns: + True or False + """ + params = {'nqn': nqn, + 'trtype': trtype} + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_set_options', params) + + def nvmf_subsystem_add_listener(client, nqn, trtype, traddr, trsvcid, adrfam, tgt_name=None): """Add a new listen address to an NVMe-oF subsystem.