diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 8fe0e9cb5..2c09da795 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -4823,6 +4823,50 @@ Example response: } ~~~ +## nvmf_subsystem_get_listeners {#rpc_nvmf_subsystem_get_listeners} + +### 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_listeners", + "params": { + "nqn": "nqn.2016-06.io.spdk:cnode1" + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "address": { + "trtype": "RDMA", + "adrfam": "IPv4", + "traddr": "192.168.0.123", + "trsvcid": "4420" + }, + "ana_state": "optimized" + } + ] +} +~~~ + ## 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 1a27a9c5d..7fe8241f6 100644 --- a/lib/nvmf/nvmf_rpc.c +++ b/lib/nvmf/nvmf_rpc.c @@ -2136,6 +2136,51 @@ dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair) spdk_json_write_object_end(w); } +static const char * +nvme_ana_state_str(enum spdk_nvme_ana_state ana_state) +{ + switch (ana_state) { + case SPDK_NVME_ANA_OPTIMIZED_STATE: + return "optimized"; + case SPDK_NVME_ANA_NON_OPTIMIZED_STATE: + return "non_optimized"; + case SPDK_NVME_ANA_INACCESSIBLE_STATE: + return "inaccessible"; + case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE: + return "persistent_loss"; + case SPDK_NVME_ANA_CHANGE_STATE: + return "change"; + default: + return NULL; + } +} + +static void +dump_nvmf_subsystem_listener(struct spdk_json_write_ctx *w, + struct spdk_nvmf_subsystem_listener *listener) +{ + const struct spdk_nvme_transport_id *trid = listener->trid; + const char *adrfam; + + spdk_json_write_object_begin(w); + + spdk_json_write_named_object_begin(w, "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_named_string(w, "ana_state", + nvme_ana_state_str(listener->ana_state)); + + spdk_json_write_object_end(w); +} + struct rpc_subsystem_query_ctx { char *nqn; char *tgt_name; @@ -2235,6 +2280,35 @@ rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem, rpc_nvmf_get_qpairs_done); } +static void +rpc_nvmf_get_listeners_paused(struct spdk_nvmf_subsystem *subsystem, + void *cb_arg, int status) +{ + struct rpc_subsystem_query_ctx *ctx = cb_arg; + struct spdk_json_write_ctx *w; + struct spdk_nvmf_subsystem_listener *listener; + + w = spdk_jsonrpc_begin_result(ctx->request); + + spdk_json_write_array_begin(w); + + for (listener = spdk_nvmf_subsystem_get_first_listener(ctx->subsystem); + listener != NULL; + listener = spdk_nvmf_subsystem_get_next_listener(ctx->subsystem, listener)) { + dump_nvmf_subsystem_listener(w, listener); + } + spdk_json_write_array_end(w); + + spdk_jsonrpc_end_result(ctx->request, 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_subsystem_query(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params, @@ -2307,3 +2381,12 @@ rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request, _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); + +static void +rpc_nvmf_subsystem_get_listeners(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + _rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_listeners_paused); +} +SPDK_RPC_REGISTER("nvmf_subsystem_get_listeners", rpc_nvmf_subsystem_get_listeners, + SPDK_RPC_RUNTIME); diff --git a/scripts/rpc.py b/scripts/rpc.py index 60ba6d17f..3ad23c848 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2012,6 +2012,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_qpairs) + def nvmf_subsystem_get_listeners(args): + print_dict(rpc.nvmf.nvmf_subsystem_get_listeners(args.client, + nqn=args.nqn, + tgt_name=args.tgt_name)) + + p = subparsers.add_parser('nvmf_subsystem_get_listeners', + help='Display listeners 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_listeners) + 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 db24e3bb6..7ffb61d87 100644 --- a/scripts/rpc/nvmf.py +++ b/scripts/rpc/nvmf.py @@ -505,6 +505,24 @@ def nvmf_subsystem_get_qpairs(client, nqn, tgt_name=None): return client.call('nvmf_subsystem_get_qpairs', params) +def nvmf_subsystem_get_listeners(client, nqn, tgt_name=None): + """Get list of listeners of an NVMe-oF subsystem. + + Args: + nqn: Subsystem NQN. + tgt_name: name of the parent NVMe-oF target (optional). + + Returns: + List of listener objects of an NVMe-oF subsystem. + """ + params = {'nqn': nqn} + + if tgt_name: + params['tgt_name'] = tgt_name + + return client.call('nvmf_subsystem_get_listeners', params) + + def nvmf_get_stats(client, tgt_name=None): """Query NVMf statistics.