diff --git a/CHANGELOG.md b/CHANGELOG.md index 552ece77c..f5f748a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ method for CHAP authentication in discovery sessions have been changed to align with `construct_target_node` RPC method. Old names are still usable but will be removed in future release. +`set_iscsi_discovery_auth` RPC method has been added to set CHAP authentication +for discovery sessions dynamically. + ## v18.07: ### bdev diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index d4c634cc7..c2bf4c582 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -1873,6 +1873,48 @@ Example response: } } ~~~ +## set_iscsi_discovery_auth method {#rpc_set_iscsi_discovery_auth} + +Set CHAP authentication for sessions dynamically. + +### Parameters + +Name | Optional | Type | Description +--------------------------- | -------- | --------| ----------- +disable_chap | Optional | boolean | CHAP for discovery session should be disabled (default: `false`) +require_chap | Optional | boolean | CHAP for discovery session should be required (default: `false`) +mutual_chap | Optional | boolean | CHAP for discovery session should be unidirectional (`false`) or bidirectional (`true`) (default: `false`) +chap_group | Optional | number | CHAP group ID for discovery session (default: 0) + +Parameters `disable_chap` and `require_chap` are mutually exclusive. + +### Example + +Example request: + +~~~ +request: +{ + "params": { + "chap_group": 1, + "require_chap": true, + "mutual_chap": true + }, + "jsonrpc": "2.0", + "method": "set_iscsi_discovery_auth", + "id": 1 +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ ## get_initiator_groups method {#rpc_get_initiator_groups} diff --git a/lib/iscsi/iscsi.h b/lib/iscsi/iscsi.h index 4dd71676e..f3fe55c66 100644 --- a/lib/iscsi/iscsi.h +++ b/lib/iscsi/iscsi.h @@ -364,6 +364,8 @@ struct spdk_iscsi_opts *spdk_iscsi_opts_alloc(void); void spdk_iscsi_opts_free(struct spdk_iscsi_opts *opts); struct spdk_iscsi_opts *spdk_iscsi_opts_copy(struct spdk_iscsi_opts *src); void spdk_iscsi_opts_info_json(struct spdk_json_write_ctx *w); +int spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, + bool mutual_chap, int32_t chap_group); void spdk_iscsi_send_nopin(struct spdk_iscsi_conn *conn); void spdk_iscsi_task_response(struct spdk_iscsi_conn *conn, diff --git a/lib/iscsi/iscsi_rpc.c b/lib/iscsi/iscsi_rpc.c index 51ffa322c..082e581fd 100644 --- a/lib/iscsi/iscsi_rpc.c +++ b/lib/iscsi/iscsi_rpc.c @@ -41,7 +41,7 @@ #include "spdk/rpc.h" #include "spdk/util.h" #include "spdk/event.h" - +#include "spdk/string.h" #include "spdk_internal/log.h" static void @@ -1057,3 +1057,51 @@ spdk_rpc_get_iscsi_global_params(struct spdk_jsonrpc_request *request, spdk_jsonrpc_end_result(request, w); } SPDK_RPC_REGISTER("get_iscsi_global_params", spdk_rpc_get_iscsi_global_params, SPDK_RPC_RUNTIME) + +struct rpc_discovery_auth { + bool disable_chap; + bool require_chap; + bool mutual_chap; + int32_t chap_group; +}; + +static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = { + {"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true}, + {"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true}, + {"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true}, + {"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true}, +}; + +static void +spdk_rpc_set_iscsi_discovery_auth(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_discovery_auth req = {}; + struct spdk_json_write_ctx *w; + int rc; + + if (spdk_json_decode_object(params, rpc_discovery_auth_decoders, + SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid parameters"); + return; + } + + rc = spdk_iscsi_set_discovery_auth(req.disable_chap, req.require_chap, + req.mutual_chap, req.chap_group); + if (rc < 0) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "Invalid combination of CHAP params"); + return; + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +} +SPDK_RPC_REGISTER("set_iscsi_discovery_auth", spdk_rpc_set_iscsi_discovery_auth, SPDK_RPC_RUNTIME) diff --git a/lib/iscsi/iscsi_subsystem.c b/lib/iscsi/iscsi_subsystem.c index 760f0dc15..23c051e8a 100644 --- a/lib/iscsi/iscsi_subsystem.c +++ b/lib/iscsi/iscsi_subsystem.c @@ -754,6 +754,26 @@ spdk_iscsi_set_global_params(struct spdk_iscsi_opts *opts) return 0; } +int +spdk_iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap, + int32_t chap_group) +{ + if (!spdk_iscsi_check_chap_params(disable_chap, require_chap, mutual_chap, + chap_group)) { + SPDK_ERRLOG("CHAP params are illegal combination\n"); + return -EINVAL; + } + + pthread_mutex_lock(&g_spdk_iscsi.mutex); + g_spdk_iscsi.disable_chap = disable_chap; + g_spdk_iscsi.require_chap = require_chap; + g_spdk_iscsi.mutual_chap = mutual_chap; + g_spdk_iscsi.chap_group = chap_group; + pthread_mutex_unlock(&g_spdk_iscsi.mutex); + + return 0; +} + static int spdk_iscsi_initialize_global_params(void) { diff --git a/scripts/rpc.py b/scripts/rpc.py index 064c741d0..c06df3d89 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -530,6 +530,25 @@ if __name__ == "__main__": p.add_argument('-u', '--min-connections-per-core', help='Allocation unit of connections per core', type=int) p.set_defaults(func=set_iscsi_options) + @call_cmd + def set_iscsi_discovery_auth(args): + rpc.iscsi.set_iscsi_discovery_auth( + args.client, + disable_chap=args.disable_chap, + require_chap=args.require_chap, + mutual_chap=args.mutual_chap, + chap_group=args.chap_group) + + p = subparsers.add_parser('set_iscsi_discovery_auth', help="""Set CHAP authentication for discovery session.""") + p.add_argument('-d', '--disable-chap', help="""CHAP for discovery session should be disabled. + *** Mutually exclusive with --require-chap""", action='store_true') + p.add_argument('-r', '--require-chap', help="""CHAP for discovery session should be required. + *** Mutually exclusive with --disable-chap""", action='store_true') + p.add_argument('-m', '--mutual-chap', help='CHAP for discovery session should be mutual', action='store_true') + p.add_argument('-g', '--chap-group', help="""Authentication group ID for discovery session. + *** Authentication group must be precreated ***""", type=int) + p.set_defaults(func=set_iscsi_discovery_auth) + @call_cmd def get_portal_groups(args): print_dict(rpc.iscsi.get_portal_groups(args.client)) diff --git a/scripts/rpc/iscsi.py b/scripts/rpc/iscsi.py index 83ad7f706..092552217 100755 --- a/scripts/rpc/iscsi.py +++ b/scripts/rpc/iscsi.py @@ -83,6 +83,37 @@ def set_iscsi_options( return client.call('set_iscsi_options', params) +def set_iscsi_discovery_auth( + client, + disable_chap=None, + require_chap=None, + mutual_chap=None, + chap_group=None): + """Set CHAP authentication for discovery service. + + Args: + disable_chap: CHAP for discovery session should be disabled (optional) + require_chap: CHAP for discovery session should be required (optional) + mutual_chap: CHAP for discovery session should be mutual (optional) + chap_group: Authentication group ID for discovery session (optional) + + Returns: + True or False + """ + params = {} + + if disable_chap: + params['disable_chap'] = disable_chap + if require_chap: + params['require_chap'] = require_chap + if mutual_chap: + params['mutual_chap'] = mutual_chap + if chap_group: + params['chap_group'] = chap_group + + return client.call('set_iscsi_discovery_auth', params) + + def get_portal_groups(client): """Display current portal group configuration.