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.