From 83eb352b3c3fb226899b19b1ce7a0590c8f3fb98 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Thu, 3 Sep 2020 09:02:44 +0900 Subject: [PATCH] lib/nvmf: Add nvmf_subsystem_get_qpairs RPC Add an new RPC, nvmf_subsystem_get_qpairs to retrieve the list of qpairs of an NVMe-oF subsystem. This RPC will be usable to verify if NVMe ANA works. Pause and resume the subsystem to access the qpairs safely. One subtle issue remains. The JSON RPC returns success even if resuming the subsystem fails. Write FIXME to address this. Signed-off-by: Shuhei Matsumoto Change-Id: I9d90a01b1117dee00d85b2e21b4f4d02d80db531 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4050 Community-CI: Broadcom CI Tested-by: SPDK CI Jenkins Reviewed-by: Aleksey Marchuk Reviewed-by: Jim Harris --- doc/jsonrpc.md | 57 ++++++++++++++++++++++++ lib/nvmf/nvmf_rpc.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ scripts/rpc.py | 11 +++++ scripts/rpc/nvmf.py | 18 ++++++++ 4 files changed, 189 insertions(+) diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index d2f053974..4496930c6 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -4723,6 +4723,63 @@ Example response: } ~~~ +## nvmf_subsystem_get_qpairs {#rpc_nvmf_subsystem_get_qpairs} + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nqn | Required | string | Subsystem NQN +tgt_name | Optional | string | Parent NVMe-oF target name. + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "method": "nvmf_subsystem_get_qpairs", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1" + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "cntlid": 1, + "qid": 0, + "state": "active", + "listen_address": { + "trtype": "RDMA", + "adrfam": "IPv4", + "traddr": "192.168.0.123", + "trsvcid": "4420" + } + }, + { + "cntlid": 1, + "qid": 1, + "state": "active", + "listen_address": { + "trtype": "RDMA", + "adrfam": "IPv4", + "traddr": "192.168.0.123", + "trsvcid": "4420" + } + } + ] +} +~~~ + ## nvmf_set_max_subsystems {#rpc_nvmf_set_max_subsystems} Set the maximum allowed subsystems for the NVMe-oF target. This RPC may only be called diff --git a/lib/nvmf/nvmf_rpc.c b/lib/nvmf/nvmf_rpc.c index 6facb4dbd..5f1d612a5 100644 --- a/lib/nvmf/nvmf_rpc.c +++ b/lib/nvmf/nvmf_rpc.c @@ -2107,6 +2107,49 @@ dump_nvmf_ctrlr(struct spdk_json_write_ctx *w, struct spdk_nvmf_ctrlr *ctrlr) spdk_json_write_object_end(w); } +static const char * +nvmf_qpair_state_str(enum spdk_nvmf_qpair_state state) +{ + switch (state) { + case SPDK_NVMF_QPAIR_UNINITIALIZED: + return "uninitialized"; + case SPDK_NVMF_QPAIR_ACTIVE: + return "active"; + case SPDK_NVMF_QPAIR_DEACTIVATING: + return "deactivating"; + case SPDK_NVMF_QPAIR_ERROR: + return "error"; + default: + return NULL; + } +} + +static void +dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair) +{ + const struct spdk_nvme_transport_id *trid = qpair->trid; + const char *adrfam; + + spdk_json_write_object_begin(w); + + spdk_json_write_named_uint32(w, "cntlid", qpair->ctrlr->cntlid); + spdk_json_write_named_uint32(w, "qid", qpair->qid); + spdk_json_write_named_string(w, "state", nvmf_qpair_state_str(qpair->state)); + + spdk_json_write_named_object_begin(w, "listen_address"); + adrfam = spdk_nvme_transport_id_adrfam_str(trid->adrfam); + if (adrfam == NULL) { + adrfam = "unknown"; + } + spdk_json_write_named_string(w, "trtype", trid->trstring); + spdk_json_write_named_string(w, "adrfam", adrfam); + spdk_json_write_named_string(w, "traddr", trid->traddr); + spdk_json_write_named_string(w, "trsvcid", trid->trsvcid); + spdk_json_write_object_end(w); + + spdk_json_write_object_end(w); +} + struct rpc_subsystem_query_ctx { char *nqn; char *tgt_name; @@ -2154,6 +2197,58 @@ rpc_nvmf_get_controllers_paused(struct spdk_nvmf_subsystem *subsystem, free_rpc_subsystem_query_ctx(ctx); } +static void +rpc_nvmf_get_qpairs_done(struct spdk_io_channel_iter *i, int status) +{ + struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i); + + spdk_json_write_array_end(ctx->w); + spdk_jsonrpc_end_result(ctx->request, ctx->w); + + if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) { + SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn); + /* FIXME: RPC should fail if resuming the subsystem failed. */ + } + + free_rpc_subsystem_query_ctx(ctx); +} + +static void +rpc_nvmf_get_qpairs(struct spdk_io_channel_iter *i) +{ + struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i); + struct spdk_io_channel *ch; + struct spdk_nvmf_poll_group *group; + struct spdk_nvmf_qpair *qpair; + + ch = spdk_get_io_channel(ctx->subsystem->tgt); + group = spdk_io_channel_get_ctx(ch); + + TAILQ_FOREACH(qpair, &group->qpairs, link) { + if (qpair->ctrlr->subsys == ctx->subsystem) { + dump_nvmf_qpair(ctx->w, qpair); + } + } + + spdk_for_each_channel_continue(i, 0); +} + +static void +rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct rpc_subsystem_query_ctx *ctx = cb_arg; + + ctx->w = spdk_jsonrpc_begin_result(ctx->request); + + spdk_json_write_array_begin(ctx->w); + + spdk_for_each_channel(ctx->subsystem->tgt, + rpc_nvmf_get_qpairs, + ctx, + rpc_nvmf_get_qpairs_done); +} + static void _rpc_nvmf_subsystem_query(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params, @@ -2218,3 +2313,11 @@ rpc_nvmf_subsystem_get_controllers(struct spdk_jsonrpc_request *request, } SPDK_RPC_REGISTER("nvmf_subsystem_get_controllers", rpc_nvmf_subsystem_get_controllers, SPDK_RPC_RUNTIME); + +static void +rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_qpairs_paused); +} +SPDK_RPC_REGISTER("nvmf_subsystem_get_qpairs", rpc_nvmf_subsystem_get_qpairs, SPDK_RPC_RUNTIME); diff --git a/scripts/rpc.py b/scripts/rpc.py index 3fcece212..60ba6d17f 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2001,6 +2001,17 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str) p.set_defaults(func=nvmf_subsystem_get_controllers) + def nvmf_subsystem_get_qpairs(args): + print_dict(rpc.nvmf.nvmf_subsystem_get_qpairs(args.client, + nqn=args.nqn, + tgt_name=args.tgt_name)) + + p = subparsers.add_parser('nvmf_subsystem_get_qpairs', + help='Display queue pairs of an NVMe-oF subsystem.') + p.add_argument('nqn', help='NVMe-oF subsystem NQN') + p.add_argument('-t', '--tgt-name', help='The name of the parent NVMe-oF target (optional)', type=str) + p.set_defaults(func=nvmf_subsystem_get_qpairs) + def nvmf_get_stats(args): print_dict(rpc.nvmf.nvmf_get_stats(args.client, tgt_name=args.tgt_name)) diff --git a/scripts/rpc/nvmf.py b/scripts/rpc/nvmf.py index 8d5ac61c8..db24e3bb6 100644 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -487,6 +487,24 @@ def nvmf_subsystem_get_controllers(client, nqn, tgt_name=None): return client.call('nvmf_subsystem_get_controllers', params) +def nvmf_subsystem_get_qpairs(client, nqn, tgt_name=None): + """Get list of queue pairs of an NVMe-oF subsystem. + + Args: + nqn: Subsystem NQN. + tgt_name: name of the parent NVMe-oF target (optional). + + Returns: + List of queue pair objects of an NVMe-oF subsystem. + """ + params = {'nqn': nqn} + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_get_qpairs', params) + + def nvmf_get_stats(client, tgt_name=None): """Query NVMf statistics.