lib/nvmf: Add nvmf_subsystem_listener_set_ana_state RPC

Add an new RPC, nvmf_subsystem_listener_set_ana_state.

Find the specified subsystem listener, and then set the ANA state
of the listener by calling nvmf_subsystem_listener_set_ana_state().

By adding a string and an enum to the existing context structure,
nvmf_rpc_listener_ctx, and adding an operation type to the existng
enum, nvmf_rpc_listen_op, reuse the existing code and data as much
as possible.

Besides, insert line break into a few long lines and fix wrong
error log.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I6fb2dfbb1f9c5f56848eba21d2a733fbed802614
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4080
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom CI
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2020-09-05 23:47:46 +09:00 committed by Tomasz Zawadzki
parent 071d80f37b
commit c8cb51d4bc
4 changed files with 245 additions and 5 deletions

View File

@ -4659,6 +4659,51 @@ Example response:
}
~~~
## nvmf_subsystem_listener_set_ana_state method {#rpc_nvmf_subsystem_listener_set_ana_state}
Set ANA state of a listener for an NVMe-oF subsystem.
### Parameters
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
ana_state | Required | string | ANA state to set ("optimized", "non_optimized", or "inaccessible")
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"method": "nvmf_subsystem_listener_set_ana_state",
"params": {
"nqn": "nqn.2016-06.io.spdk:cnode1",
"listen_address": {
"trtype": "RDMA",
"adrfam": "IPv4",
"traddr": "192.168.0.123",
"trsvcid": "4420"
},
"ana_state", "inaccessible"
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
## nvmf_subsystem_add_ns method {#rpc_nvmf_subsystem_add_ns}
Add a namespace to a subsystem. The namespace ID is returned as the result.

View File

@ -588,6 +588,7 @@ free_rpc_listen_address(struct rpc_listen_address *r)
enum nvmf_rpc_listen_op {
NVMF_RPC_LISTEN_ADD,
NVMF_RPC_LISTEN_REMOVE,
NVMF_RPC_LISTEN_SET_ANA_STATE,
};
struct nvmf_rpc_listener_ctx {
@ -597,6 +598,8 @@ struct nvmf_rpc_listener_ctx {
struct spdk_nvmf_transport *transport;
struct spdk_nvmf_subsystem *subsystem;
struct rpc_listen_address address;
char *ana_state_str;
enum spdk_nvme_ana_state ana_state;
struct spdk_jsonrpc_request *request;
struct spdk_nvme_transport_id trid;
@ -616,6 +619,7 @@ 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->ana_state_str);
free(ctx);
}
@ -658,7 +662,8 @@ nvmf_rpc_subsystem_listen(void *cb_arg, int status)
if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
if (!ctx->response_sent) {
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Internal error");
}
nvmf_rpc_listener_ctx_free(ctx);
/* Can't really do anything to recover here - subsystem will remain paused. */
@ -670,15 +675,38 @@ nvmf_rpc_stop_listen_async_done(void *cb_arg, int status)
struct nvmf_rpc_listener_ctx *ctx = cb_arg;
if (status) {
SPDK_ERRLOG("Unable to remove listener.\n");
SPDK_ERRLOG("Unable to stop listener.\n");
spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"error stopping listener: %d\n", status);
"error stopping listener: %d", status);
ctx->response_sent = true;
}
if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
if (!ctx->response_sent) {
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Internal error");
}
nvmf_rpc_listener_ctx_free(ctx);
/* Can't really do anything to recover here - subsystem will remain paused. */
}
}
static void
nvmf_rpc_set_ana_state_done(void *cb_arg, int status)
{
struct nvmf_rpc_listener_ctx *ctx = cb_arg;
if (status) {
SPDK_ERRLOG("Unable to set ANA state.\n");
spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"error setting ANA state: %d", status);
ctx->response_sent = true;
}
if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
if (!ctx->response_sent) {
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Internal error");
}
nvmf_rpc_listener_ctx_free(ctx);
/* Can't really do anything to recover here - subsystem will remain paused. */
@ -714,13 +742,18 @@ nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem,
spdk_nvmf_transport_stop_listen_async(ctx->transport, &ctx->trid, nvmf_rpc_stop_listen_async_done,
ctx);
return;
} else if (ctx->op == NVMF_RPC_LISTEN_SET_ANA_STATE) {
nvmf_subsystem_set_ana_state(subsystem, &ctx->trid, ctx->ana_state,
nvmf_rpc_set_ana_state_done, ctx);
return;
} else {
SPDK_UNREACHABLE();
}
if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_listen_resumed, ctx)) {
if (!ctx->response_sent) {
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Internal error");
}
nvmf_rpc_listener_ctx_free(ctx);
/* Can't really do anything to recover here - subsystem will remain paused. */
@ -919,6 +952,108 @@ rpc_nvmf_subsystem_remove_listener(struct spdk_jsonrpc_request *request,
SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", rpc_nvmf_subsystem_remove_listener,
SPDK_RPC_RUNTIME);
static const struct spdk_json_object_decoder nvmf_rpc_set_ana_state_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},
{"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string},
{"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true},
};
static int
rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state)
{
if (ana_state == NULL || str == NULL) {
return -EINVAL;
}
if (strcasecmp(str, "optimized") == 0) {
*ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
} else if (strcasecmp(str, "non_optimized") == 0) {
*ana_state = SPDK_NVME_ANA_NON_OPTIMIZED_STATE;
} else if (strcasecmp(str, "inaccessible") == 0) {
*ana_state = SPDK_NVME_ANA_INACCESSIBLE_STATE;
} else {
return -ENOENT;
}
return 0;
}
static void
rpc_nvmf_subsystem_listener_set_ana_state(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct nvmf_rpc_listener_ctx *ctx;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_nvmf_tgt *tgt;
ctx = calloc(1, sizeof(*ctx));
if (!ctx) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Out of memory");
return;
}
ctx->request = request;
if (spdk_json_decode_object(params, nvmf_rpc_set_ana_state_decoder,
SPDK_COUNTOF(nvmf_rpc_set_ana_state_decoder),
ctx)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
nvmf_rpc_listener_ctx_free(ctx);
return;
}
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,
"Unable to find a target.\n");
nvmf_rpc_listener_ctx_free(ctx);
return;
}
ctx->tgt = tgt;
subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
if (!subsystem) {
SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Unable to find subsystem with NQN %s",
ctx->nqn);
nvmf_rpc_listener_ctx_free(ctx);
return;
}
ctx->subsystem = subsystem;
if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
nvmf_rpc_listener_ctx_free(ctx);
return;
}
if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
nvmf_rpc_listener_ctx_free(ctx);
return;
}
ctx->op = NVMF_RPC_LISTEN_SET_ANA_STATE;
if (spdk_nvmf_subsystem_pause(subsystem, nvmf_rpc_listen_paused, ctx)) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Internal error");
nvmf_rpc_listener_ctx_free(ctx);
}
}
SPDK_RPC_REGISTER("nvmf_subsystem_listener_set_ana_state",
rpc_nvmf_subsystem_listener_set_ana_state, SPDK_RPC_RUNTIME);
struct spdk_nvmf_ns_params {
char *bdev_name;
char *ptpl_file;

View File

@ -1919,6 +1919,26 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('-s', '--trsvcid', help='NVMe-oF transport service id: e.g., a port number')
p.set_defaults(func=nvmf_subsystem_remove_listener)
def nvmf_subsystem_listener_set_ana_state(args):
rpc.nvmf.nvmf_subsystem_listener_set_ana_state(args.client,
nqn=args.nqn,
ana_state=args.ana_state,
trtype=args.trtype,
traddr=args.traddr,
tgt_name=args.tgt_name,
adrfam=args.adrfam,
trsvcid=args.trsvcid)
p = subparsers.add_parser('nvmf_subsystem_listener_set_ana_state', help='Set ANA state of a listener for an NVMe-oF subsystem')
p.add_argument('nqn', help='NVMe-oF subsystem NQN')
p.add_argument('-n', '--ana-state', help='ANA state to set: optimized, non-optimized, or inaccessible', required=True)
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_listener_set_ana_state)
def nvmf_subsystem_add_ns(args):
rpc.nvmf.nvmf_subsystem_add_ns(args.client,
nqn=args.nqn,

View File

@ -330,6 +330,46 @@ def nvmf_subsystem_remove_listener(
return client.call('nvmf_subsystem_remove_listener', params)
def nvmf_subsystem_listener_set_ana_state(
client,
nqn,
ana_state,
trtype,
traddr,
trsvcid,
adrfam,
tgt_name=None):
"""Set ANA state of a listener for an NVMe-oF subsystem.
Args:
nqn: Subsystem NQN.
ana_state: ANA state to set ("optimized", "non_optimized", or "inaccessible").
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:
True or False
"""
listen_address = {'trtype': trtype,
'traddr': traddr,
'trsvcid': trsvcid}
if adrfam:
listen_address['adrfam'] = adrfam
params = {'nqn': nqn,
'listen_address': listen_address,
'ana_state': ana_state}
if tgt_name:
params['tgt_name'] = tgt_name
return client.call('nvmf_subsystem_listener_set_ana_state', params)
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.